Python Dynamic Class Methods
Solution 1:
You can achieve this by using a __getattr__
hook on a metaclass.
classDefaultClassMethods(type):
def__getattr__(cls, attr):
def_defaultClassMethod(cls):
print'Hi, I am the default class method!'setattr(cls, attr, classmethod(_defaultClassMethod))
returngetattr(cls, attr)
Demo:
>>>classDefaultClassMethods(type):...def__getattr__(cls, attr):...def_defaultClassMethod(cls):...print'Hi, I am the default class method!'...setattr(cls, attr, classmethod(_defaultClassMethod))...returngetattr(cls, attr)...>>>classA(object):... __metaclass__ = DefaultClassMethods...>>>A.spam
<bound method DefaultClassMethods._defaultClassMethod of <class '__main__.A'>>
>>>A.spam()
Hi, I am the default class method!
Note that we set the result of the classmethod
call straight onto the class, effectively caching it for future lookups.
If you need to regenerate the class method on every call instead, use the same method to bind a function to an instance but with the class and metaclass instead (using cls.__metaclass__
to be consistent with metaclass subclassing):
from types import MethodType
classDefaultClassMethods(type):
def__getattr__(cls, attr):
def_defaultClassMethod(cls):
print'Hi, I am the default class method!'return _defaultClassMethod.__get__(cls, cls.__metaclass__)
For static methods just return the function directly in all cases, no need to muck with the staticmethod
decorator or the descriptor protocol.
Solution 2:
The behaviors provided to instances by methods like __getattr__
and the descriptor protocol can work for classes as well, but in that case, you have to code them in the class's metaclass.
In this case, all one needs to do is to set the metaclass __getattr__
function to auto-generate the desired class attribute.
(The setattr, getattr trick is to let Python do the function->method transoform with no need to mess with it)
classAutoClassMethod(type):
def__getattr__(cls, attr):
default = classmethod(lambda cls: "Default class method for " + repr(cls))
setattr(cls, attr, default)
returngetattr(cls, attr)
classA(object):
__metaclass__ = AutoClassMethod
@classmethoddefb(cls):
print cls
Solution 3:
>>>classC(object):...pass...>>>C.m = classmethod(lambda cls: cls.__name__)>>>C.m()
'C'
Or you can use somethigs like this:
classWrapper(object):
def__init__(self, clz, default=lambda cls: None):
self._clz = clz
self._default = default
def__getattr__(self, attr):
# __attrs__ will be getted from Wrapperif attr.startswith('__'):
return self.__getattribute__(attr)
ifnothasattr(self._clz, attr):
setattr(self._clz, attr, classmethod(self._default))
returngetattr(self._clz, attr)
def__call__(self, *args, **kwargs):
return self._clz(*args, **kwargs)
>>> classC(object):
... pass
...
>>> C = Wrapper(C, default=lambda cls: cls.__name__)
>>> c = C()
>>> print C.m()
'C'>>> print c.m() # now instance have method "m"'C'
Post a Comment for "Python Dynamic Class Methods"