我有以下類別:裝飾方法有不同的方法的簽名
class A(object):
@classmethod
def result(cls):
raise NotImplementedError
@classmethod
def square(cls, **kwargs):
r = cls.result(**kwargs)
return r ** 2
class B(A):
@classmethod
def result(cls):
return 2
class C(A):
@classmethod
def result(cls, *, x, y):
return x + y
A類的方法square
不知道的result
實施呢,因此獲得通用**kwargs
接受任何東西,將其傳遞給result
。
我想包裝square
的方式,它需要子實現的函數簽名result
。因此,當我檢查
inspect.getfullargspec(C.square)
inspect.getfullargspec(C.result)
# both return FullArgSpec(args=['cls'], varargs=None, varkw=None, defaults=None, kwonlyargs=['x', 'y'], kwonlydefaults=None, annotations={})
什麼是最好的方法來做到這一點?
functools.wraps
正在爲名稱和文檔執行此操作,但不是用於簽名。 boltons.funcutils.wraps
爲名稱,文檔和簽名執行此操作。我想要簽名,但不是名稱和文檔。另外,在我的特定用例中,這些方法是類方法。
編輯:
我已經得到了一個包裝,以這兩個類和實例工作,具有boltons.funcutils.wraps
和元類:
from boltons.funcutils import wraps
# from functools import wraps
from inspect import getfullargspec
def wrap_if_result_signature_desired(self, super, item):
if item in ['square']:
return self._signature_wrapper(super.__getattribute__(item))
return super.__getattribute__(item)
class WrappingMetaClass(type):
def __getattribute__(self, item):
return wrap_if_result_signature_desired(self, super(), item)
class A(object, metaclass=WrappingMetaClass):
def __getattribute__(self, item):
return wrap_if_result_signature_desired(self, super(), item)
@classmethod
def _signature_wrapper(cls, f):
@wraps(cls.result)
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
wrapper.__name__ = f.__name__
wrapper.__doc__ = f.__doc__
return wrapper
@classmethod
def result(cls):
raise NotImplementedError
@classmethod
def square(cls, **kwargs):
r = cls.result(**kwargs)
return r ** 2
class B(A):
@classmethod
def result(cls):
return 2
class C(A):
@classmethod
def result(cls, *, x, y):
return x + y
print(getfullargspec(C.square))
print(getfullargspec(C().square))
# FullArgSpec(args=['cls'], varargs=None, varkw=None, defaults=None, kwonlyargs=['x', 'y'], kwonlydefaults=None, annotations={})
# FullArgSpec(args=['cls'], varargs=None, varkw=None, defaults=None, kwonlyargs=['x', 'y'], kwonlydefaults=None, annotations={})
但是,方法本身不因爲boltons.funcutils工作。包裹返回一個函數而不是一個綁定方法。因此:
#Both do not work
print(C.square(x=1,y=2))
print(C().square(x=1,y=2))
# print(C.square(x=1,y=2))
# TypeError: result() missing 1 required positional argument: 'cls'
注:使用functools.wraps
作品在某種意義上說,代碼運行(顯然functools.wraps不將其綁定到類),但是,它並沒有接過簽名,這是整個目的這個練習的第一位。
我所知,沒有以編程方式創建一個功能Python在運行時定義的簽名。除了使用'compile'或直接的AST操作,當然,如果你出於某種原因希望你的裝飾函數具有特定的簽名,這可能是一種有效的方法。你爲什麼需要它?如果你更詳細地解釋了更大的問題,那麼幫助會更容易。 – 9000
只是回答了一個裝飾者的方法問。 –
@ 9000基類實現不同模型的共同特徵,其中每個模型以不同的方式實現「結果」方法。我們知道共同特徵需要與'結果'方法相同的參數。如果您認爲不同的代碼設計更合適,我絕對有興趣。 – RickB