如何找出缺少哪个Python关键字参数?
当忘记将某些参数传递给函数时,Python会给出唯一有用的消息“myfunction()接受X个参数(Y给定)”。有没有办法找出缺失参数的名称并告诉用户?比如:如何找出缺少哪个Python关键字参数?,python,inspect,keyword-argument,Python,Inspect,Keyword Argument,当忘记将某些参数传递给函数时,Python会给出唯一有用的消息“myfunction()接受X个参数(Y给定)”。有没有办法找出缺失参数的名称并告诉用户?比如: try: #begin blackbox def f(x,y): return x*y f(x=1) #end blackbox except Exception as e: #figure out the missing keyword argument is called "
try:
#begin blackbox
def f(x,y):
return x*y
f(x=1)
#end blackbox
except Exception as e:
#figure out the missing keyword argument is called "y" and tell the user so
假设异常处理程序不知道begin blackbox和end blackbox之间的代码
编辑:正如下面向我指出的,Python3已经内置了这个功能。那么,让我扩展一下这个问题,在Python2.x中是否有一种(可能是丑陋的和黑客的)方法来实现这一点
except TypeError as e:
import inspect
got_args = int(re.search("\d+.*(\d+)",str(e)).groups()[0])
print "missing args:",inspect.getargspec(f).args[got_args:]
一个更好的方法是一个装饰师
def arg_decorator(fn):
def func(*args,**kwargs):
try:
return fn(*args,**kwargs)
except TypeError:
arg_spec = inspect.getargspec(fn)
missing_named = [a for a in arg_spec.args if a not in kwargs]
if arg_spec.defaults:
missing_args = missing_named[len(args): -len(arg_spec.defaults) ]
else:
missing_args = missing_named[len(args):]
print "Missing:",missing_args
return func
@arg_decorator
def fn1(x,y,z):
pass
def fn2(x,y):
pass
arged_fn2 = arg_decorator(fn2)
fn1(5,y=2)
arged_fn2(x=1)
我认为这样做没有多大意义。由于程序员没有指定参数,因此引发了这样的异常。因此,如果您有意捕获异常,那么您也可以首先修复它 也就是说,在当前的Python 3版本中,抛出的
TypeError
确实提到调用中缺少哪些参数:
"f() missing 1 required positional argument: 'y'"
不幸的是,没有单独提到参数名称,因此您必须从字符串中提取它:
try:
f(x=1)
except TypeError as e:
if 'required positional argument' in e.args[0]:
argumentNames = e.args[0].split("'")[1::2]
print('Missing arguments are ' + argumentNames)
else:
raise # Re-raise other TypeErrors
正如Joran Beasley在评论中指出的那样,Python2不会告诉您缺少哪些参数,而是告诉您缺少多少参数。因此,无法从异常中判断调用中缺少了哪些参数。一种更简洁的方法是将函数包装到另一个函数中,通过
*args、**kwargs
,然后在需要时使用这些值,而不是事后尝试重新构建它们。但是如果你不想那样做
正如poke的回答所解释的,在Python3.x中(非常早期的版本除外),这很简单。使用3.3+、与和朋友更轻松
在Python2.x中,没有办法做到这一点。该异常只有字符串'f()在其参数中正好取2个参数(1个给定)
除了…特别是在CPython2.x中,有足够的丑陋和脆弱的黑客是可能的
你有一个回溯,所以你有它的tb\u帧
和tb\u行
…这就是你所需要的一切。因此,只要源代码可用,该模块就可以轻松获得实际的函数调用表达式。然后,您只需解析它(via)就可以获得传递的参数,并与函数的签名进行比较(不幸的是,在2.x中获得签名并不像在3.3+中那么容易,但是在f.func_默认值
,f.func_code.co_argcount
等之间,您可以重构它)
但是如果来源不可用怎么办?在tb\u frame.f\u code
和tb\u lasti
之间,您可以找到函数调用在字节码中的位置。这个模块使得解析相对容易。特别是,就在调用之前,位置参数和关键字参数的名称-值对都被推送到堆栈上,因此您可以很容易地看到哪些名称被推,以及有多少位置值,并以这种方式重构函数调用。以同样的方式将其与签名进行比较
当然,这取决于关于CPython编译器如何构建字节码的一些假设。以各种不同的顺序进行操作是完全合法的,只要堆栈最终具有正确的值。所以,它很脆。但是我认为已经有更好的理由不这样做了。除了处理例外,不可能做你想做的事情和处理关键字参数。这当然是WRTPython2.7
在Python中生成此消息的代码是:
PyErr_Format(PyExc_TypeError,
"%.200s() takes %s %d "
"argument%s (%d given)",
PyString_AsString(co->co_name),
defcount ? "at most" : "exactly",
co->co_argcount,
co->co_argcount == 1 ? "" : "s",
argcount + kwcount);
取自第3056-3063行
正如您所看到的,对于异常缺少哪些参数,没有提供足够的信息<在此上下文中,code>co
是被调用的PyCodeObject
。给出的唯一内容是一个字符串(如果愿意,可以对其进行解析),其中包含函数名、是否存在vararg、需要多少个参数以及给出了多少个参数。正如已经指出的,这并没有为您提供关于哪些参数没有给出的足够信息(在关键字参数的情况下)
类似于inspect
或其他调试模块的功能可能能够为您提供足够的信息,说明调用了什么函数以及如何调用它,您可以从中找出哪些参数没有给出
不过,我还应该提到,几乎可以肯定的是,您提出的任何解决方案都将无法处理至少一些扩展模块方法(用C编写的方法),因为它们不提供参数信息作为对象的一部分。@CrazyCasta这并没有真正回答这个问题……这是一个有用且相关的问题,但不是复制品。人们对投票结果非常满意,所以这些天……这是为哪个版本的Python设计的?对于非常早期的2.x、之后的2.x、非常早期的3.x和之后的3.x,答案是不同的。请注意,当前的Python3将为您提供这些信息。升级!:)@马吕斯:如果这只是一个练习……现在可能是开始玩回溯、框架、代码对象、
inspect.getsource
、dis.dis
,等等的好时机。但实际上,我认为你最好先转到Python 3.4,在那里,所有这些都比2.7更容易、更清晰、更有趣,而您所获得的知识在将来将是有价值的。对于python 2.6来说,这是不正确的至少aa()在python中正好使用了2个非关键字参数(给定1个)
indexer2@wim我在2中得到了TypeError。6@wim嗯,为了哪一行?这是在Python 3.1+(我想……可能是3.2+)中最简单也是最好的方法。它不适用于2.x或3.0,但在那里没有简单的方法。exeption消息中的数字不会告诉您缺少哪个参数,而是告诉您缺少多少参数。请尝试f(y=5)