清晰的demo搞定python的元类(metaclass)中attrs的使用

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'

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值