在cPython 2.4中:
def f(a,b,c,d):
pass
>>> f(b=1,c=1,d=1)
TypeError: f() takes exactly 4 non-keyword arguments (0 given)
但:
>>> f(a=1,b=1,c=1)
TypeError: f() takes exactly 4 non-keyword arguments (3 given)
显然,我真的非常了解Python的函数参数处理机制。有人愿意分享一下这个吗?我看到发生了什么(比如填充参数插槽,然后放弃),但我认为这会导致一个新手。
(另外,如果人们有更好的问题关键词 - 类似“胆量” - 请重新加入)
答案 0 :(得分:13)
当你说
时def f(a,b,c,d):
你告诉python f
需要4个位置参数。每次拨打f
时,必须提供4个参数,第一个值将分配给a
,第二个值将分配给b
等。
您可以使用类似
的内容来致电f
f(1,2,3,4)
或f(a=1,b=2,c=3,d=4)
,甚至f(c=3,b=2,a=1,d=4)
但在所有情况下,必须提供4个参数。
f(b=1,c=1,d=1)
返回错误,因为没有为a
提供任何值。 (0给出)
f(a=1,b=1,c=1)
返回错误,因为没有为d
提供任何值。 (3给出)
给出的args数表示在实现错误之前python已经达到了多远。
顺便说一下,如果你说
def f(a=1,b=2,c=3,d=4):
然后你告诉python f
需要4个可选参数。如果未给出某个arg,则会自动为您提供其默认值。然后你可以通过调用
f(a=1,b=1,c=1)
或f(b=1,c=1,d=1)
答案 1 :(得分:0)
理论上,可以用更清晰,更丰富的内容包装生成的TypeError。但是,有许多小细节,其中一些我不知道如何解决。
注意:以下代码是一个勉强工作的示例,而不是一个完整的解决方案。
try:
fn(**data)
except TypeError as e:
## More-sane-than-default processing of a case `parameter ... was not specified`
## XXX: catch only top-level exceptions somehow?
## * through traceback?
if fn.func_code.co_flags & 0x04: ## XXX: check
# it accepts `*ar`, so not the case
raise
f_vars = fn.func_code.co_varnames
f_defvars_count = len(fn.func_defaults)
## XXX: is there a better way?
## * it catches `self` in a bound method as required. (also, classmethods?)
## * `inspect.getargspec`? Imprecise, too (for positional args)
## * also catches `**kwargs`.
f_posvars = f_vars[:-f_defvars_count]
extra_args = list(set(data.keys()) - set(f_vars))
missing_args = list(set(f_posvars) - set(data.keys()))
if missing_args: # is the case, raise it verbosely.
msg = "Required argument(s) not specified: %s" % (
', '.join(missing_args),)
if extra_args:
msg += "; additionally, there are extraneous arguments: %s" % (
', '.join(extra_args))
raise TypeError(msg, e)
#_log.error(msg)
#raise
raise