如何动态更改子类中方法的签名?

时间:2017-08-11 03:45:19

标签: python class methods signature

当使用 classmethod 动态更改子类中的方法时,如何动态更改方法的签名?

示例

import inspect

class ModelBase(object):

    @classmethod
    def method_one(cls, *args):
        raise NotImplementedError

    @classmethod
    def method_two(cls, *args):
        return cls.method_one(*args) + 1

class SubClass(ModelBase):
    @staticmethod
    def method_one(a, b):
        return a + b

test = SubClass()

try:
    print(inspect.signature(test.method_two))
except AttributeError:
    print(inspect.getargspec(test.method_two).args)

我希望test.method_two获得test.method_one的签名。如何重写父类ModelBase

我读过Preserving signatures of decorated functions。在python3.4 +中,functools.wraps有助于保留修饰函数的签名。我想将它应用于类方法。

使用functools.wraps时,我需要指定装饰方法的名称。但是在这种情况下如何在classmethod之外访问修饰方法?

from functools import wraps

class ModelBase(object):

    @classmethod
    def method_one(cls, *args):
        raise NotImplementedError

    @classmethod
    def method_two(cls):
        @wraps(cls.method_one)
        def fun(*args):
            return cls.method_one(*args) + 1
        return fun

method_two返回一个包装函数,但我必须将它与test.method_two()(*arg)一起使用。这种方法不是直接的。

1 个答案:

答案 0 :(得分:1)

如果这仅用于内省目的,您可以覆盖__getattribute__上的ModelBase,并且每次访问method_two时,我们都会返回一个签名为method_one的函数。< / p>

import inspect

def copy_signature(frm, to):
    def wrapper(*args, **kwargs):
        return to(*args, **kwargs)
    wrapper.__signature__ = inspect.signature(frm)
    return wrapper


class ModelBase(object):

    @classmethod
    def method_one(cls, *args):
        raise NotImplementedError

    @classmethod
    def method_two(cls, *args):
        return cls.method_one(*args) + 1

    def __getattribute__(self, attr):
        value = object.__getattribute__(self, attr)
        if attr == 'method_two':
            value = copy_signature(frm=self.method_one, to=value)
        return value


class SubClass(ModelBase):
    @staticmethod
    def method_one(a, b):
        return a + b


class SubClass2(ModelBase):
    @staticmethod
    def method_one(a, b, c, *arg):
        return a + b

<强>演示:

>>> test1 = SubClass()
>>> print(inspect.signature(test1.method_two))
(a, b)
>>> test2 = SubClass2()
>>> print(inspect.signature(test2.method_two))
(a, b, c, *arg)