getattr works pretty well with instance of class:
class Person:
def __getattr__(self, name):
print(name)
p = Person()
p.john
Output:
john
but it does not work as classmethod:
class Person:
@classmethod
def __getattr__(cls, name):
print(name)
Person.john
Output:
AttributeError: type object 'Person' has no attribute 'john'
Is there a way to use getattr for class directly ?
CodePudding user response:
__getattr__
, like most special methods, is only looked up on the class of the instance (bypassing the instance itself). Since you're trying to call it on the class itself, it has to be defined on the class that class Person
is implementing. By default that's type
(the common root for all class types).
If you really need to do this (I suspect an XY problem) you can do this with a metaclass (the class of the class itself):
class PersonMeta(type):
def __getattr__(cls, name):
print(cls, name)
class Person(metaclass=PersonMeta):
def __getattr__(self, name):
return getattr(type(self), name) # Delegate to metaclass implementation
Person.john
Person().john
Note that you need to implement a delegating version on the class itself to ensure it delegates back to the metaclass's implementation (assuming you want to be able to have it function on instances of the class, not just on the class itself). The metaclass itself could dynamically attach such a method to the class at construction time (in __prepare__
or __new__
) if all instances of the metaclass's classes should exhibit this delegation behavior.