Python的动态类方法(Python dynamic class methods)

2019-06-25 23:00发布

说有:

class A(B):
    ...

其中, B可能是object...不是

@classmethod # or @staticmethod
def c(cls): print 'Hello from c!'

我有什么做的,调用Ac()不会触发AttributeError

换句话说,我知道它是可以手动类方法在运行时添加到一个类。 但是,它可以自动执行此操作,说的每一个类的方法缺少它会创建一些虚拟方法时?

在又一个的话,只有我能不能代替A.__dict__我的字典它处理__getitem__ -但A.__dict__似乎是不可写...

Answer 1:

您可以通过使用一个实现这一__getattr__钩子上的元类 。

class DefaultClassMethods(type):
    def __getattr__(cls, attr):
        def _defaultClassMethod(cls):
            print 'Hi, I am the default class method!'
        setattr(cls, attr, classmethod(_defaultClassMethod))
        return getattr(cls, attr)

演示:

>>> class DefaultClassMethods(type):
...     def __getattr__(cls, attr):
...         def _defaultClassMethod(cls):
...             print 'Hi, I am the default class method!'
...         setattr(cls, attr, classmethod(_defaultClassMethod))
...         return getattr(cls, attr)
... 
>>> class A(object):
...     __metaclass__ = DefaultClassMethods
... 
>>> A.spam
<bound method DefaultClassMethods._defaultClassMethod of <class '__main__.A'>>
>>> A.spam()
Hi, I am the default class method!

请注意,我们设置的结果classmethod调用直接到类,有效地缓存,以备日后查询。

如果您需要重新在每次调用类的方法来代替,使用相同的方法将功能捆绑到一个实例 ,但与类和元类,而不是(使用cls.__metaclass__要与元类的子类一致):

from types import MethodType

class DefaultClassMethods(type):
    def __getattr__(cls, attr):
        def _defaultClassMethod(cls):
            print 'Hi, I am the default class method!'
        return _defaultClassMethod.__get__(cls, cls.__metaclass__)

对于静态方法只是在所有情况下直接返回功能,无需与淤泥staticmethod装饰或描述符协议。



Answer 2:

通过类似的方法提供的实例的行为__getattr__和描述符协议可以为班级工作为好,但在这种情况下,你必须将它们在类的元类代码。

在这种情况下,所有需要做的是设置元类__getattr__功能自动生成所需的类属性。

(该SETATTR,GETATTR诀窍就是让Python的做,没有必要惹它的功能 - >方法transoform)

class AutoClassMethod(type):
    def __getattr__(cls, attr):
        default = classmethod(lambda cls: "Default class method for " + repr(cls))
        setattr(cls, attr, default)
        return getattr(cls, attr)



class A(object):
    __metaclass__ = AutoClassMethod
    @classmethod
    def b(cls):
        print cls


Answer 3:

>>> class C(object):
...     pass
... 
>>> C.m = classmethod(lambda cls: cls.__name__)
>>> C.m()
'C'

或者你可以用这样的somethigs:

class Wrapper(object):

    def __init__(self, clz, default=lambda cls: None):
        self._clz = clz
        self._default = default

    def __getattr__(self, attr):
        # __attrs__ will be getted from Wrapper
        if attr.startswith('__'):
            return self.__getattribute__(attr)

        if not hasattr(self._clz, attr):
            setattr(self._clz, attr, classmethod(self._default))
        return getattr(self._clz, attr)

    def __call__(self, *args, **kwargs):
        return self._clz(*args, **kwargs)

>>> class C(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'


文章来源: Python dynamic class methods