代码之家  ›  专栏  ›  技术社区  ›  Gregg Lind

误导(?)向用位置参数定义的函数传递关键字参数时出现TypeError

  •  8
  • Gregg Lind  · 技术社区  · 15 年前

    在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的函数参数处理机制。有人想和我们分享一下吗?我知道发生了什么(比如填补争论的空缺,然后放弃),但我认为这会给新手带来麻烦。

    (另外,如果人们有更好的问题关键词,比如“guts”,请重新标记)

    2 回复  |  直到 15 年前
        1
  •  13
  •   unutbu    15 年前

    当你说

    def f(a,b,c,d):
    

    你是在告诉蟒蛇 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) 返回错误,因为没有为提供值 f(a=1,b=1,c=1) 返回错误,因为没有为提供值 d . (给出3个)

    给定的参数数表示python在意识到有错误之前已经走了多远。

    顺便说一下,如果你说

    def f(a=1,b=2,c=3,d=4):
    

    那你就告诉蟒蛇 需要4分钟 可选择的 论据。如果未给定某个参数,则会自动为您提供其默认值。那你就可以不打电话了

    f(a=1,b=1,c=1) f(b=1,c=1,d=1)

        2
  •  0
  •   HoverHell    12 年前

    从理论上讲,可以用更清晰、信息更丰富的内容来包装由此产生的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