GetAttr 在元类中引发 AttributeErorr
GetAttr raises AttributeErorr in metaclass
我正在研究 python 以了解它是如何工作的,但有些东西很奇怪。我在我的 MetaClass 中定义了一个 __new__
方法,我希望第四个参数(这是 class-to-be 属性的字典)包含我的 [=34] 中定义的方法=]准身材
我有这个代码:
#!/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')
,但 returns 也是错误的。
字典不会将键公开为属性。该词典将成为正在创建的 class 的命名空间,但它 还不是 class 的一部分。 类(及其元class)有一个 __getattribute__
method 将属性访问转换为字典查找,但这在字典对象本身上不可用。
只需使用字典订阅权限:
print(attrs['foobar'])
或调用 super().__new__()
,存储 return 值,然后查找新 class 对象的属性:
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)
不会产生实例!它 return 是 super()
代理对象,其属性将在元class 方法解析顺序 (MRO) 上查找。 super(MyMetaClass, metacls).__new__
就是这样一个查找,在 metaclass 的 MRO 中找到下一个 __new__
属性。在本例中是 type.__new__
,调用该方法会生成实际的 class 对象。
我正在研究 python 以了解它是如何工作的,但有些东西很奇怪。我在我的 MetaClass 中定义了一个 __new__
方法,我希望第四个参数(这是 class-to-be 属性的字典)包含我的 [=34] 中定义的方法=]准身材
我有这个代码:
#!/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')
,但 returns 也是错误的。
字典不会将键公开为属性。该词典将成为正在创建的 class 的命名空间,但它 还不是 class 的一部分。 类(及其元class)有一个 __getattribute__
method 将属性访问转换为字典查找,但这在字典对象本身上不可用。
只需使用字典订阅权限:
print(attrs['foobar'])
或调用 super().__new__()
,存储 return 值,然后查找新 class 对象的属性:
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)
不会产生实例!它 return 是 super()
代理对象,其属性将在元class 方法解析顺序 (MRO) 上查找。 super(MyMetaClass, metacls).__new__
就是这样一个查找,在 metaclass 的 MRO 中找到下一个 __new__
属性。在本例中是 type.__new__
,调用该方法会生成实际的 class 对象。