发布时间:2024-06-08 09:01
class my_meta(type):
def __init__(self, *args):
print(\'__init__\')
def __call__(self, *args, **kwargs):
print(\'__call__\')
return super(my_meta, self).__call__()
def __new__(cls, *args, **kwargs):
print(\'__new__\')
return super(my_meta, cls).__new__(cls, *args, **kwargs)
class T(metaclass=my_meta):
def __init__(self):
print(\"init\")
pass
def __call__(self, *args, **kwargs):
print(\"call\")
def __new__(cls, *args, **kwargs):
print(\"new\")
return super().__new__(cls, *args, **kwargs)
def __setattr__(self, key, value):
print(\'setattr\')
super(T, self).__setattr__(key, value)
def __getattr__(self, item):
print(\'getattr\')
return self.__dict__.get(item)
def __setitem__(self, key, value):
print(\'setitem\')
super(T, self).__setattr__(key, value)
def __getitem__(self, item):
print(\'getitem\')
return self.__dict__.get(item)
def __getattribute__(self, item):
print(\'get_attribute\')
return super(T, self).__getattribute__(item)
if __name__ == \'__main__\':
t = T()
print(\'-\' * 90)
t.name = \'z\'
t[\'nn\'] = \'nn\'
print(t.nn)
print(\'x\'*99)
print(t.nn)
print(t[\'nn\'])
print(\'-\' * 90)
print(t.z)
# print(t[\'z\'])
程序运行结果为
__new__
__init__
__call__
new
init
------------------------------------------------------------------------------------------
setattr
setitem
get_attribute
nn
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
get_attribute
nn
getitem
get_attribute
nn
------------------------------------------------------------------------------------------
get_attribute
getattr
get_attribute
None
接下来来分析结果,首先,类是由元类(metaclass)创建的,当Python解释器运行到 class T时,会调用元类的__new__()来创建一个类,然后调用__init__()实例化对象,这个就是T类。当解释器执行到 t=T()时,类名加括号会调用元类的__call__()方法(因为T是由my_meta创建的,T是它的一个实例,实例加括号会调用它类的call方法),再调用类的__new__创建、__init__初始化并返回创建的实例,也就是t。
类实例的所有属性都会保存在__dict__中。
当使用 类实例.xx时(t.xx)会调用类的__getattribute__()函数,如果报错或者为找到则会继续调用getattr方法,xx会当作getattr函数的key参数传进去。
类实例[\'xx\'](t[\'xx\'])会调用getitem方法,参数与getattr一致,当未找到值时也调用__getattribute__方法。
使用赋值语句时(t[\'xx\']=\'xx\' \\ t.xx=‘xxx\')会调用对应的set方法(setitem或setattr)setattr可调用父类的setattr来将值设置进去。