有没有办法获得传递给函数的实际参数数量
def foo(a, optional=42):
if ????
print "1 arg"
else:
print "2 args"
foo(11) # should print 1 arg
foo(22, 42) # should print 2 args
不更改其签名以接受*args
?
答案 0 :(得分:6)
您可以将默认值更改为sentinel:
_sentinel = object()
def foo(a, optional=_sentinel):
if optional is _sentinel:
optional = 42
print "1 arg"
else:
print "2 args"
或直接在func_defaults
元组中访问它:
def foo(a, optional=object()):
if optional is foo.func_defaults[0]:
optional = 42
print "1 arg"
else:
print "2 args"
但实际上并没有使用它;这只会使那些不熟悉标准函数对象属性的人感到困惑。
是的,_sentinel
对象是内省的,并且仍然可以由一个坚定的开发人员获得,但是同样的开发人员可以再次对你的函数进行monkeypatch。 : - )
答案 1 :(得分:6)
您可以使用装饰器来做到这一点。从Preserving signatures of decorated functions问题我们知道如何正确执行此操作。
import decorator
@decorator.decorator
def count_args(f):
def new(*args, **kwargs):
kwargs['nargs'] = len(args)+len(kwargs)
return f(*args, **kwargs)
return new
@count_args
def foo(a, optional=42, nargs=1):
print nargs
foo(1) # 1
foo(1, 4) # 2
foo(1, optional=4) # 2
<强>更新强>
我刚刚为我们传递给函数的args数添加了关键字参数。 如您所见,默认情况下为1,即True。 这看起来像一个黑客,但它的确有效。
答案 2 :(得分:0)
我会使用装饰器:
def wrapper(func):
def wrapped(*args):
if len(args) == 2:
print "2 arg"
else:
print "1 arg"
return wrapped
@wrapper
def foo(a,optional=None):
pass
foo(11)
#1 arg
foo(22, 42)
#2 arg