簡體   English   中英

將關鍵字參數傳遞給使用位置參數定義的函數時,會產生誤導(?)TypeError

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM