metaclass可以使用attrs访问、修改子类的属性(or 成员)。其中是class的属性,不是(创建之后的如self.after_cunstucted)对象的。例子中,从Test.in_metaclass_c的访问可以知道是class而不是对象t的成员。
输出I think I will be interpreted first!在一系列Test的成员被打印之后才看到,所以Test是被定义之后马上生成,而不是等到有语句(print("I ..."))才执行。
python中一切都是对象,__init__也被看成class的属性(attrs可以访问),都可以被映射到attrs,然后也被pop了。self.defined_in_constructor自然就不存在了。
所以在pop(当然,很少会全部pop完)完之后,元类的派生类只存在attrs指定的属性。
代码和例子:
class TestMetaclass(type):
def __new__(cls, name, bases, attrs):
mappings = dict()
# 这一句打印class Test中的属性(which 保存在attrs中)
# 就连__init__也会被视为对象而pop掉(被print为__qualname__ Test)
for k, v in attrs.items():
print(k, v)
mappings[k] = v
for k in mappings.keys():
attrs.pop(k)
attrs['in_metaclass_get_str'] = lambda self, arg: '%s' % arg
# 反正是随便一个值,2333
attrs['in_metaclass_c'] = 2333
return type.__new__(cls, name, bases, attrs)
class Test(object, metaclass = TestMetaclass):
'''
这是一个__doc__对象。
这个class里面的元素先进行初始化,也就是先生成。
接下来就会被metaclass影响,也就是print,然后在pop
所以还是能够知道他们执行的顺序是:先原来的版本,然后在被metaclass影响。
Bye~
'''
a = 'A member in Test'
b = 'Another member in Test'
# 不会被执行,在被Metaclass影响后的被pop
def __init__(self, defined_in_constructor):
# 不,你不行,被pop了
print("I think I can work...")
self.defined_in_constructor = defined_in_constructor
print('I think I will be interpreted first!')
# 可以看到,不传递参数都能够调用,并不是原来版本的class Test版本中的__init__
t = Test()
print(t.in_metaclass_get_str('I called in_metaclass_get_str')) # 输出:I called in_metaclass_get_str
# 直接使用Test,表面属性是Class的,不是单独属于对象t的
print(Test.in_metaclass_c) # 输出:2333
# 已经被Metaclass中的代码给pop掉了
print(t.defined_in_constructor)
结果:
__module__ __main__
__qualname__ Test
__doc__
这是一个__doc__对象。
这个class里面的元素先进行初始化,也就是先生成。
接下来就会被metaclass影响,也就是print,然后在pop
所以还是能够知道他们执行的顺序是:先原来的版本,然后在被metaclass影响。
Bye~
a A member in Test
b Another member in Test
__init__ <function Test.__init__ at 0x7f587e4110d0>
f <function Test.f at 0x7f587e46a048>
I think I will be interpreted first!
I called in_metaclass_get_str
2333
Traceback (most recent call last):
File "t.py", line 42, in <module>
print(t.defined_in_constructor)
AttributeError: 'Test' object has no attribute 'defined_in_constructor'