获取Python中类和实例的属性
在Python中,下面的代码可以工作:
class MyClass(object):
field = 1
>>> MyClass.field
1
>>> MyClass().field
1
当我想要返回自定义字段的值时,我会使用下面的代码:
class MyClass(object):
def __getattr__(self, name):
if name.startswith('fake'):
return name
raise AttributeError("%r object has no attribute %r" %
(type(self).__name__, name))
>>> MyClass().fake
fake
但是:
>>> MyClass.fake
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: class MyClass has no attribute 'fake'
好吧,对于类,我可以使用下面的代码:
class MyClassMeta(type):
def __getattr__(cls, name):
if name.startswith('fake'):
return name
raise AttributeError("%r object has no attribute %r" %
(type(self).__name__, name))
class MyClass(object):
__metaclass__ = MyClassMeta
>>> MyClass.fake
fake
但是:
>>> MyClass().fake
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute 'fake'
为了解决这个问题,我使用下面的代码:
class FakeAttrMixin():
def __getattr__(self, name):
if name.startswith('fake'):
return name
raise AttributeError("%r object has no attribute %r" %
(type(self).__name__, name))
class MyClassMeta(type, FakeAttrMixin):
pass
class MyClass(object, FakeAttrMixin):
__metaclass__ = MyClassMeta
>>> MyClass.fake
fake
>>> MyClass().fake
fake
MyClass.fake
会调用 __getattr__
,传入 MyClass
和 fake
作为参数。
MyClass().fake
会调用 __getattr__
,传入 MyClass
的实例和 fake
作为参数。
如果我只在我的混合类中实现 __getattr__
的逻辑,而不使用 self
参数,这样是可以的。
我能否以更优雅的方式编写类和实例的自定义值解析?为什么 MyClass.field
和 MyClass().field
的 field
值解析在定义为 MyClass(object): field = 1
时表现不同,而与 __getattr__
方法相比?因为当我想获取 field
时,它首先会在实例中查找,然后在类中查找,但我不明白为什么 __getattr__
的工作方式不同。
类似的问题有: __getattr__ 在类和实例上的区别 以及 访问实例属性和类属性的区别。
1 个回答
不,如果你需要同时支持在类和实例上查找任意属性,那你唯一的办法就是在元类和类上各实现一个 __getattr__
钩子方法,一个用来支持类的查找,另一个用来支持实例的查找。
这是因为特殊的钩子方法总是会在类型上查找,所以会用到 type(obj).__getattr__
。因此,对于 MyClass.fake
,会使用元类的 __getattr__
。你可以查看 新风格类的特殊方法查找;我在 之前的回答 中解释过为什么会这样。
简单来说,在你的情况下,MyClass.fake
会变成 MyClass.__getattr__('fake')
,而 __getattr__
是一个未绑定的方法,它需要两个参数(self
和 name
),这样就会出错。