Python 自省与反射
自省
In computing, type introspection is the ability of a program to examine the type or properties of an object at runtime. Some programming languages possess this capability.
在计算机科学中,内省是指计算机程序在运行时(Run time)检查对象(Object)类型(以及属性等)的一种能力,通常也可以称作运行时类型检查。
方法 | 作用 | 类型 |
---|---|---|
help() | 查看函数或者模块用途的详细说明 | 自省 |
dir() | 返回对象所有属性 | 自省 |
type() | 查看对象类型 | 自省 |
isinstance() | 判断一个对象是否是一个已知的类型 | 自省 |
issubclass() | 判断一个类是不是另一个类的子类 | 自省 |
id() | 返回地址值 | 自省 |
callable() | 判断对象是否可调用 | 自省 |
自省的常见使用方式
help()
help() 函数用于查看函数或模块用途的详细说明。主要在IDE环境下使用,接受任何拥有函数或者方法的对象,打印出对象所有的函数和文档字符串。
1 | Welcome to Python 3.6's help utility! |
对于自定义的类、函数、或者模块等,也可以打印帮助信息。
1 | class Demo: |
dir()
dir() 函数可能是 Python 自省机制中最著名的部分了。它返回传递给它的任何对象的属性名称经过排序的列表。如果不指定对象,则dir() 返回当前作用域中的名称。
dir() 函数适用于所有对象类型,包括字符串、整数、列表、元组、字典、函数、定制类、类实例和类方法。
1 | # 查看当前作用域中的属性名称 |
将 dir() 运用于定制类、类实例和属性,下例可以说明 Python 自省能力的动态本质
1 | class Person(object): |
注意 dir() vs help()
- dir() : 只是得到方法或者属性的名称
- help() : 不但可以得到对象的方法和属性名称, 同时也可以得到这些方法或者属性的使用方式的描述
type()
type() 函数属于 Python 内置函数,通常用来查看某个变量的具体类型。其实,type() 函数还有一个更高级的用法,即创建一个自定义类型(也就是创建一个类)。
type() 函数的语法格式有 2 种,分别如下:
- *type(obj) *
用来查看某个变量(类对象)的具体类型,obj 表示某个变量或者类对象。
- type(name, bases, dict)
用来创建类,其中 name 表示类的名称;bases 表示一个父类的元组;dict 表示一个字典,即类内定义的属性方法和值组成的键值对。
1 | # 示例 |
注意:type vs object
type为对象的顶点,所有对象都创建自type。
object为类继承的顶点,所有类都继承自object。
python中万物皆对象,一个python对象可能拥有两个属性,__class__
和 __base__
,__class__
表示这个对象是谁创建的,__base__
表示一个类的父类是谁。
1 | print(object.__class__) |
- type类继承自object
- object的对象创建自type
isinstance()
1 | # 相关源码 |
issubclass()
1 | # 相关源码 |
1 | # 示例 |
注意:
is vs ==
is 是去判断这两个是不是一个对象, 即 id 是否相同
== 是判断值是否相等
(ob1 is ob2) 等价于 (id(ob1) == id(ob2))
1 | # 示例 |
type() vs isinstance()
type() 用于求一个未知数据类型的对象,isinstance() 用于判断一个对象是否是已知类型;
type() 不认为子类是父类的一种类型,isinstance() 认为子类是父类的一种类型,即子类对象也属于父类类型
id()
1 | # 相关源码 |
id() 函数返回对象的唯一标识符,标识符是一个整数。
CPython 中 id() 函数用于获取对象的内存地址。
callable()
1 | # 相关源码 |
- 该方法用来检测对象是否可被调用,可被调用——指的是对象能否使用()括号的方法调用。
- 可调用对象,在实际调用也可能调用失败;但是不可调用对象,调用肯定不成功。
- 类对象都是可被调用对象,类的实例对象是否可调用对象,取决于类是否定义了
__call__
方法。 - 也就是说,对于函数、方法、lambda 函式、 类以及实现了
__call__
方法的类实例, 它都返回 True。
1 | # 示例 |
反射
Introspection should not be confused with reflection, which goes a step further and is the ability for a program to manipulate the values, meta-data, properties and/or functions of an object at runtime.
也就是说自省和反射不是同一回事,自省是获取对象类型的能力,而反射是操纵对象的值,元数据,属性和/或函数的能力。
在计算机学中,反射(英语:reflection)是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
在Python中反射非常简单,用起来几乎感觉不到与其他的代码有区别,使用反射获取到的函数和方法可以像平常一样加上括号直接调用,获取到类后可以直接构造实例;不过获取到的字段不能直接赋值,因为拿到的其实是另一个指向同一个地方的引用,赋值只能改变当前的这个引用而已。
方法 | 作用 | 类型 |
---|---|---|
hasattr() | 判断类方法或者类属性是否存在,返回一个布尔值,存在返回True,反之返回Flase | 反射 |
getattr() | 获取属性值或实例方法,如果其不存在,会抛出一个AttributeError 异常 |
反射 |
setattr() | 设置实例属性的值,如果实例属性不存在时,会自动给当前实例添加该属性 | 反射 |
delattr() | 删除实例的属性或者实例的方法,当其不存在时同样会抛出一个AttributeError 异常 |
反射 |
反射的应用场景
1 | # 示例 |
反射主要根据字符串去寻找类的属性值,主要用于用户交互,触发类内函数运行,根据字符串动态的判断,调用,添加/修改,删除类或类的实例化对象中的方法或属性。
反射在 web 框架中用的很多,通过解析url,执行对应不同的功能。
反射还可以用于动态导入模块 ,如下所示:
1 | # 示例 |