【问题标题】:How to dynamically change signatures of method in subclass?如何动态更改子类中方法的签名?
【发布时间】:2017-08-11 03:45:18
【问题描述】:

当使用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) 一起使用。这个方法不是直接的。

【问题讨论】:

    标签: python class methods signature


    【解决方案1】:

    如果这只是出于自省目的,您可以在 ModelBase 上覆盖 __getattribute__,并且每次访问 method_two 时,我们都会返回一个具有 method_one 签名的函数。

    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)
    

    【讨论】:

    • 谢谢!它适用于 CodeGen。为method_two做codegen,需要method_one的签名。
    猜你喜欢
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 1970-01-01
    相关资源
    最近更新 更多