2017-08-11 27 views
1

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

例如

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

如果这仅仅是为了反省的目的,你可以在ModelBase每一次method_two覆盖__getattribute__我们返回具有的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) 
+0

谢谢!这是CodeGen的。要为method_two执行codegen,它需要method_one的签名。 – Ryan