In python work next code:
class MyClass(object):
field = 1
>>> MyClass.field
1
>>> MyClass().field
1
When I want return value for custom fields I use next code:
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
But:
>>> MyClass.fake
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: class MyClass has no attribute 'fake'
Ok, for classes I can use next code:
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
But:
>>> MyClass().fake
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute 'fake'
To resolve this problem I use next code:
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 will call __getattr__ with MyClass and fake arguments.
MyClass().fake will call __getattr__ with MyClass instance and fake arguments.
And it's ok if I implement __getattr__ logic only on my mixin and don't use self argument.
Can I write custom value resolving by class and instance more beautiful and why field value resolving for MyClass.field and MyClass().field with MyClass(object): field = 1 definition works different if compare with __getattr__ method? Because when I want get field it at first searching in instance, then in class, but I can't understand why __getattr__ works another way.
Similar questions: __getattr__ on a class and not (or as well as) an instance and Difference between accessing an instance attribute and a class attribute.