代码之家  ›  专栏  ›  技术社区  ›  Florian

getAttr在元类中引发attributeOrr

  •  0
  • Florian  · 技术社区  · 7 年前

    我在玩弄巨蟒来理解它是如何工作的,但是有一些奇怪的东西。我在定义 __new__ 方法在我的元类中,我希望第四个参数(它是类属性的dict)包含在我的类中定义的方法为body。

    我有这个代码:

    #!/usr/bin/python3
    
    
    class MyMetaClass(type):
        def __new__(metacls, name, bases, attrs):
            instance = super(MyMetaClass, metacls) #Create instance of super class, which metaclass is type
            print(type(type))
            print(type(type(instance)))
            print(instance.__new__)
            print(type.__new__)
            print(attrs)
            print(getattr(attrs, 'foobar'))
            return super(MyMetaClass, metacls).__new__(metacls, name, bases, attrs)
    
    class TestClass(metaclass=MyMetaClass):
        def __get__(self, obj, type=None):
            return self
        def foobar(self):
            print(f'My name is {self.name}') 
        def __init__(self, args):
            print(args)
            self.firstname = args['firstname'] if 'firstname' in args else ''
            self.lastname = args['lastname'] if 'lastname' in args else ''
            self.name = f'{self.firstname} {self.lastname}'
    
    
    
    data = {'firstname': 'Florian'}
    c = TestClass(data)
    c.foobar()
    

    输出为:

    <class 'type'>
    <class 'type'>
    <built-in method __new__ of type object at 0x10d759e40>
    <built-in method __new__ of type object at 0x10d759e40>
    {'__module__': '__main__', '__qualname__': 'TestClass', '__get__': <function TestClass.__get__ at 0x10e192b70>, 'foobar': <function TestClass.foobar at 0x10e192bf8>, '__init__': <function TestClass.__init__ at 0x10e192c80>}
    Traceback (most recent call last):
      File "<stdin>", line 25, in <module>
      File "<string>", line 13, in <module>
      File "<string>", line 10, in __new__
    AttributeError: 'dict' object has no attribute 'foobar'
    

    所以 print(attrs) 在里面 MyMetaClass.__new__ 结果如预期的那样:

    {'__module__': '__main__', '__qualname__': 'TestClass', '__get__': <function TestClass.__get__ at 0x7f042b9e6158>, 'foobar': <function TestClass.foobar at 0x7f042b9e61e0>, '__init__': <function TestClass.__init__ at 0x7f042b9e6268>}
    

    你怎么看,它包含“foobar”键。

    然而,下一行上升 AttributeError : 'dict' object has no attribute 'foobar' .为什么?

    我试过了 hasattr(attrs, 'foobar') 也会返回假。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Martijn Pieters    7 年前

    字典不会将键作为属性公开。字典将成为正在创建的类的命名空间,但它是 还没上过课 .类(及其元类)具有 __getattribute__ method 它将属性访问转换为字典查找,但字典对象本身不可用。

    只需使用字典订阅访问:

    print(attrs['foobar'])
    

    或者打电话 super().__new__() ,存储返回值,然后查找该新类对象的属性:

    class MyMetaClass(type):
        def __new__(metacls, name, bases, attrs):
            new_class = super(MyMetaClass, metacls).__new__(metacls, name, bases, attrs)
            print(new_class.foobar)
            return new_class
    

    注: super(MyMetaClass, metacls) 生成一个实例!它返回 super() 代理对象,其属性将在元类方法解析顺序(MRO)上查找。 super(MyMetaClass, metacls).__new__ 是这样的查找,查找下一个 __new__ 元类的mro中的属性。在这种情况下,这是 type.__new__ ,并调用该方法生成实际的类对象。