假设Python库中有一个函数(我们称之为mymodule
):
def some_func(a,b='myDefaultValue'):
return some_computation
然后另一个模块中的另一个函数调用它,
import mymodule
def wrapper(a,b):
return some_transform(mymodule.some_func(a,b))
如何使wrapper
继承some_func
对b
参数的默认值?我可以这样写:
def wrapper(a,b=None):
if b:
return some_transform(some_func(a,b))
else:
return some_transform(some_func(a))
,但这似乎不必要的麻烦,导致多个可选参数的组合爆炸的可能性,并使得我不能显式地传递None
给wrapper
。
是否有一种方法可以获得函数的默认参数,或者通常的做法是简单地将该值拉到两个函数声明都可以使用的共享常量中?
可以使用func_defaults:https://docs.python.org/2/library/inspect.html?highlight=func_defaults types-and-members
func_defaults元组,包含所有参数的默认值
def some_func(a,b='myDefaultValue'):
print a, b
def wrapper(a,b):
b = some_func.func_defaults[0] if b is None else b
some_func(a,b)
print "b is 'there'"
a = "hello"
b = "there"
wrapper(a,b)
print "b is 'None'"
b = None
wrapper(a,b)
输出:b is 'there'
hello there
b is 'None'
hello myDefaultValue
EDIT:要从评论中回答您的问题,没有任何内置的东西可以按名称查找具有默认值的函数的参数。但是,您知道具有默认值的参数必须在非可选参数之后。如果你知道你的参数总数,以及其中有多少是默认值,你可以减去2来得到默认值参数的起始点。然后,您可以将参数列表(从先前计算的参数索引开始)与默认参数值列表压缩在一起,并从该列表创建一个字典。使用inspect模块获取所需的所有信息:
一样:
>>> import inspect
>>> def some_func(a,b,c,d="dee",e="ee"):
... print a,b,c,d,e
...
>>> some_func("aaa","bbb","ccc",e="EEE")
aaa bbb ccc dee EEE
>>> some_funcspec = inspect.getargspec(some_func)
>>> some_funcspec
ArgSpec(args=['a', 'b', 'c', 'd', 'e'], varargs=None, keywords=None, defaults=('dee', 'ee'))
>>> defargsstartindex = len(some_funcspec.args) - len(some_funcspec.defaults)
>>> defargsstartindex
3
>>> namedargsdict = dict(zip([key for key in some_funcspec.args[defargsstartindex:]], list(some_funcspec.defaults)))
>>> namedargsdict
{'e': 'ee', 'd': 'dee'}
在上面的例子中,namedargsdict是some_func
默认值的参数列表。
进一步阅读:
https://docs.python.org/2/library/inspect.html inspect.getargspec
inspect.getargspec(func)获取Python的名称和默认值函数的参数。返回包含四个元素的元组:(args,可变参数、关键字、默认值)。Args是参数名称的列表可能包含嵌套列表)。变量和关键字是*的名称和**参数或None。Defaults是一个包含default参数的元组值,如果没有默认参数则为None;如果这个元组有n元素,它们对应args中列出的最后n个元素。
在2.6版更改:返回一个命名元组ArgSpec(args, varargs,关键词,违约)。
您可以使用参数解包来完成此操作:
In [1]: def some_func(a,b='myDefaultValue'):
...: print a, b
...:
In [2]: def wrapper(a, *args, **kwargs):
...: some_func(a, *args, **kwargs)
...:
In [3]: some_func('foo', 'bar')
foo bar
In [4]: some_func('baz')
baz myDefaultValue
In [5]: wrapper('foo', 'bar')
foo bar
In [6]: wrapper('baz')
baz myDefaultValue
如果你打算用这种方式包装多个函数,你可以考虑把wrapper
作为装饰器:
In [1]: from functools import wraps
In [2]: def wrapper(func):
...: @wraps(func)
...: def decorated(a, *args, **kwargs):
...: print 'wrapper invoked with a = {}'.format(a)
...: return func(a, *args, **kwargs)
...: return decorated
...:
In [3]: @wrapper
...: def some_func(a, b='myDefaultValue'):
...: print a, b
...:
In [4]: some_func('foo', 'bar')
wrapper invoked with a = foo
foo bar
In [5]: some_func('baz')
wrapper invoked with a = baz
baz myDefaultValue
你的问题不够清楚。但就我从你的问题中理解,你应该使用class
,这样你就可以很容易地在类
class SomeClass:
def __init__(self, b='defaultvalue'):
self.b = b
def some_func(self, a, b):
pass
def wrapper(self, a):
self.some_func(a, self.b)