系列文章目录
一、反射(reflect)
-
概念:
反射是一种机制,是指在程序运行过程中,实现动态获取对象信息以及动态使用(导入、调用等)的机制。
-
作用:
反射机制被视为动态语言的关键。它可以让程序在事先不知道对象里面包含什么成员的情况下,获取并使用对象里面的成员。
二、使用反射机制
-
四个与反射相关的函数:
hasattr(对象, '属性'[,默认值])
:判断对象是否拥有该属性,有的话返回True
;没有的话返回False
,如果有默认值则返回默认值getattr(对象, '属性')
:获取属性,相当于对象.属性
setattr(对象, '属性', '值')
:修改属性的值,相当于对象.属性=值
delattr(对象, '属性')
:删除属性,相当于del 对象.属性
-
举例:
用户输入功能,调用对应的方法:
class Foo(): def login(): print('登录') def logout(): print('登出') def register(): print('注册') # 注意:inp是字符串类型 inp = input('请输入功能:') foo = Foo() # 判断用户输入的功能是否包含在foo对象中 if hasattr(foo, inp): # 通过用户输入的字符串反射到foo的同名方法上 func = getattr(foo, inp) func()
此处使用了
xxxattr
的四个方法,免去了判断用户输入,调用对应方法的步骤,极大的方便了我们编程。
三、元类
python之中,一切皆对象!
-
元类的概念:
类也是一种对象,我们在实例化一个对象的时候,都会通过该对象的类来实例化,那么一个类对象是通过什么来“实例化”的呢?答案就是元类!
python中内置的元类是
type
,是它产生了所有的类对象(内置的、自定义的类)。 -
class
关键字创建类的步骤:-
传类名
-
传父类
-
运行类体代码,拿到类体的命名空间
-
调用元类
一个类由3部分组成:类名、父类、类体(类体的命名空间)。
class就是将这三部分进行处理后,传给type,完成了类对象的生成:
class_name = 'Foo' class_base = (object,) class_body = {} a = type(class_name, class_base, class_body) print(a) # 打印:<class '__main__.Foo'>
在产生类对象的时候,也会像产生实例对象那样,调用元类中的初始化方法。
-
-
自定义元类:
自己定义一个类,继承type类,这个自定义类就成了元类。
之后在要“实例化”自定义元类,产生类对象的地方,传入
metaclass=自定义元类
关键字参数即可。class MyMeta(type): """自定义元类""" # 注意:在调用元类的时候需要传入类名、父类、类体命名空间,所以这里至少需要三个额外的位置形参来接受这三个实参 def __init__(self, name, base, body): print('调用元类的初始化方法!') class Foo(metaclass=MyMeta): """属于自定义元类的普通类""" def __init__(self, name): self.name = name # 打印:调用元类的初始化方法!
self
是指自定义元类的对象,此处是Foo
。 -
__new()__
方法:
在元类创建类对象时,会优先于__init__()
方法之前调用该方法。
__new__()
方法返回一个空的类对象,这个空对象会传递给__init__(self)
方法中的self
参数。class MyMeta(type): """自己定义的一个元类""" def __new__(cls, *args, **kwargs): print('调用了__new__方法') # 调用元类的父类中的__new__方法,创建空的类对象并返回 return super().__new__(cls, *args, **kwargs) class Foo(metaclass=MyMeta): pass # 打印:调用了__new__方法
-
__call__()
方法:
当使用()
调用一个对象的时候,其实调用的是对象内部的__call__()
方法。
当调用一个类(类对象)时,会依次触发其元类内的__new__()
方法、__init__()
方法和__call__()
方法。产生的类对象便是__call__()
的返回值。 -
成员查找:
在查找对象的成员时(即在
对象.成员
时),会从对象所属类开始查找,再查找父类,一直到object(即最顶级的父类)处停止,不会去元类(默认的或自定义的)中查找。在查找类的成员时(即在
类.成员
时),则不会在object(即最顶级的父类)处停止,还会继续在自定义元类、type类中查找。