2017-08-11 69 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