Python(2.7):动态添加classmethods

时间:2012-11-11 23:51:57

标签: python

我有一些类的方法,我希望能够在其他类中添加。我最初的解决方案是使用mixins,但这可能会有点难看:

class Schedule(Enumerator, Humanizer, Inferer, ...):
    ...

所以我觉得嘿,也许我可以使用类装饰器来达到同样的效果。

@enumerator
@humanizer
@inferer
class Schedule(object):
    ...

以下是装饰器功能的示例:

import inspect

def inferer(original_class):
    from myproj.lib.inferer import Inferer
    methods = inspect.getmembers(Inferer, predicate=inspect.ismethod)
    for method in methods:
        setattr(original_class, method[0], types.MethodTypes(method[1], original_class))
    return original_class

...似乎将方法和类方法适当地添加到装饰类中。但是,当我在装饰类上调用其中一个添加的方法(或classmethods)时,我会遇到一些错误。

方法:

>>> Schedule().humanize()
TypeError: unbound method humanize() must be called with Humanizer instance as first argument (got type instance instead)

...这似乎表明这些是作为classmethods添加的?

对于classmethods:

>>> schedule = Schedule.infer(foo)
TypeError: infer() takes exactly 2 arguments (3 given)

请注意推断的定义:

class Inferer(object):
    @classmethod
    def infer(cls, dates):
        ...

我向infer添加了一些行,以显示调用Schedule.infer()时获得的参数:

cls: <class 'myproj.lib.inferer.Inferer'>
dates: <class 'myproj.Schedule'>

所以,我的问题:

装饰器函数出了什么问题导致这些添加的方法和类方法行为奇怪?或者,更好的说,如何修改装饰器功能以正确处理这些添加?

如果我能就任何一点提供任何澄清,请告诉我。

1 个答案:

答案 0 :(得分:4)

让我们说这是一个好主意。这是您实现它的一种方式。我不能说我会建议它。

def horrible_class_decorator_factory(mixin):
    def decorator(cls):
        d = cls.__dict__.copy()
        bases = tuple([b for b in cls.__bases__ if b != object] + [mixin])
        return type(cls.__name__, bases, d)
    return decorator

现在你可以这样做:

class Inferer(object):
    @classmethod
    def foo(cls):
        return "bar" + cls.__name__

inferer = horrible_class_decorator_factory(Inferer)

@inferer
class X(object):
    pass

X.foo()
"barX"

我和这个评论者在一起。仅仅因为你可以做某事并不意味着你应该这样做。