3

在 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__withMyClassfakearguments。

MyClass().fake将调用实例和__getattr__参数。MyClassfake

__getattr__如果我只在我的 mixin 上实现逻辑并且不使用self参数,那也没关系。

我可以编写更漂亮的类和实例的自定义值解析吗?如果与方法相比,为什么值解析和定义的field工作MyClass.field方式不同?因为当我想首先在实例中搜索时,然后在课堂上,但我不明白为什么以另一种方式工作。MyClass().fieldMyClass(object): field = 1__getattr__field__getattr__

类似的问题:类上的 __getattr__ 而不是(或以及)实例访问实例属性和类属性之间的区别

4

1 回答 1

3

不,如果您必须同时支持对类和实例的任意属性查找,那么您唯一的选择是__getattr__在元类和类上实现一个钩子方法,每个方法都支持对类和实例的查找。

这是因为特殊的钩子方法总是在类型上查找,所以type(obj).__getattr__. 因此,MyClass.fake使用元类__getattr__。请参阅新式类的特殊方法查找;我解释了为什么这是在以前的答案中。

简短的原因是,在您的情况下,MyClass.fake将转换为MyClass.__getattr__('fake')然后__getattr__是一个未绑定的方法,需要两个参数(selfname),这将失败。

于 2013-03-13T14:13:26.400 回答