我有以下课程:
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
和MetaClasses为类和实例提供了一个包装工具:
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.wraps返回函数而不是绑定方法,因此方法本身不起作用。因此:
#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确实将它绑定到类),然而,它并没有接管签名,这是整个目的首先是这项练习。
答案 0 :(得分:0)
我提出了这个解决方案:
Param(
[alias('foop')]
[string]$MyWord = 'hi'
)
function myfunc ([string] $MyWord){
Write-Host "$MyWord"
}
# Add all unbound parameters that have default values.
$boundAndDefaultValueParams = $PSBoundParameters
foreach($paramName in $MyInvocation.MyCommand.Parameters.Keys) {
if (-not $boundAndDefaultValueParams.ContainsKey($paramName)) {
$val = Get-Variable $paramName -ValueOnly
if ($null -ne $val) { $boundAndDefaultValueParams.Add($paramName, $val) }
}
}
myfunc @boundAndDefaultValueParams
输出:
import inspect
def inspect_result_signature(f):
def inner(cls, *args, **kwargs):
signature = inspect.getargspec(cls.result)
print cls.__name__, ':', signature
return f(cls, *args, **kwargs)
return inner
class A(object):
@classmethod
def result(cls):
raise NotImplementedError
@classmethod
@inspect_result_signature
def square(cls, *args, **kwargs):
r = cls.result(*args, **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 B.square()
print C.square(2, 2)
对于Python3,您必须使用$ python signature.py
<class '__main__.B'> () {}
B : ArgSpec(args=['cls'], varargs=None, keywords=None, defaults=None)
4
<class '__main__.C'> (2, 2) {}
C : ArgSpec(args=['cls', 'x', 'y'], varargs=None, keywords=None, defaults=None)
16
或inspect.getfullargspec