[英]Misleading(?) TypeError when passing keyword arguments to function defined with positional arguments
在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的函數 - 參數處理機制。 有人願意分享一下這個嗎? 我看到發生了什么(比如填充參數插槽,然后放棄),但我認為這會毀掉一個新手。
(另外,如果人們有更好的問題關鍵詞 - 類似“膽量” - 請重拍)
當你說
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)
從理論上講,可以用更清晰,更豐富的內容包裝生成的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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.