我正在创建一个简单的命令行实用程序,并使用字典作为一种case语句,其关键字链接到其相应的函数。这些函数都有不同数量的参数,因此目前要检查用户是否输入了每个函数所需的正确数量的参数,我将所需的金额放在{Keyword:(FunctionName, AmountofArguments)}
形式的字典case语句中。
这个当前的设置工作得非常好,但我只是想知道自我改进的利益,如果有一种方法来确定一个函数中所需的参数数量,我的谷歌尝试返回到目前为止没有任何价值,但我看到如何由于他们允许的论据数量无限,args和kwargs可以搞砸这样的命令。
答案 0 :(得分:40)
获取函数参数的名称和默认值。返回四个元组的元组:(args,varargs,varkw,defaults)。 args是参数名称的列表(它可能包含嵌套列表)。 varargs和varkw是*和**参数的名称或None。 defaults是默认参数值的元组,如果没有默认参数,则为None;如果这个元组有n个元素,它们对应于args中列出的最后n个元素。
答案 1 :(得分:15)
你想要的通常是不可能的,因为使用了varargs和kwargs,但inspect.getargspec
(Python 2.x)和inspect.getfullargspec
(Python 3.x)接近。
Python 2.x:
>>> import inspect
>>> def add(a, b=0):
... return a + b
...
>>> inspect.getargspec(add)
(['a', 'b'], None, None, (0,))
>>> len(inspect.getargspec(add)[0])
2
Python 3.x:
>>> import inspect
>>> def add(a, b=0):
... return a + b
...
>>> inspect.getfullargspec(add)
FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(0,), kwonlyargs=[], kwonlydefaults=None, annotations={})
>>> len(inspect.getfullargspec(add).args)
2
答案 2 :(得分:4)
在Python 3中,使用someMethod.__code__.co_argcount
(因为someMethod.func_code.co_argcount
不再有效)
答案 3 :(得分:2)
这已经得到解答,但如果没有检查模块,您也可以使用someMethod.func_code.co_argcount
答案 4 :(得分:1)
使每个命令成为一个类,派生自定义命令一般结构的抽象基础。应尽可能地将命令属性的定义放入类变量中,并使用在处理该数据的基类中定义的方法。
使用工厂类注册每个子类。 此工厂类获取参数列表,通过实例化相应的命令子类来决定执行哪个命令。
参数检查由命令子类本身处理,使用命令基类中正确定义的通用方法。
这样,您永远不需要重复编码相同的东西,并且实际上不需要模拟switch语句。它还可以非常轻松地扩展和添加命令,因为您可以简单地添加和注册新类。没有什么可以改变的。
答案 5 :(得分:0)
很好的问题。我只是遇到了一个问题,我想编写一个带回调参数的函数。根据该回调的参数数量,需要以不同方式调用它。
我从gimel的回答开始,然后扩展为能够处理与inspect
模块(raise TypeError
)反应不佳的内置函数。
所以这里是检查函数是否只需要一个参数的代码:
def func_has_one_arg_only(func, typical_argument=None, ignore_varargs=False):
"""True if given func expects only one argument
Example (testbench):
assert not func_has_one_arg_only(dict.__getitem__), 'builtin 2 args'
assert func_has_one_arg_only(lambda k: k), 'lambda 1 arg'
assert not func_has_one_arg_only(lambda k,x: k), 'lambda 2 args'
assert not func_has_one_arg_only(lambda *a: k), 'lambda *a'
assert not func_has_one_arg_only(lambda **a: k), 'lambda **a'
assert not func_has_one_arg_only(lambda k,**a: k), 'lambda k,**a'
assert not func_has_one_arg_only(lambda k,*a: k), 'lambda k,*a'
assert func_has_one_arg_only(lambda k: k, ignore_varargs=True), 'lambda 1 arg'
assert not func_has_one_arg_only(lambda k,x: k, ignore_varargs=True), 'lambda 2 args'
assert not func_has_one_arg_only(lambda *a: k, ignore_varargs=True), 'lambda *a'
assert not func_has_one_arg_only(lambda **a: k, ignore_varargs=True), 'lambda **a'
assert func_has_one_arg_only(lambda k,**a: k, ignore_varargs=True), 'lambda k,**a'
assert func_has_one_arg_only(lambda k,*a: k, ignore_varargs=True), 'lambda k,*a'
"""
try:
import inspect
argspec = inspect.getargspec(func)
except TypeError: # built-in c-code (e.g. dict.__getitem__)
try:
func(typical_argument)
except TypeError:
return False
else:
return True
else:
if not ignore_varargs:
if argspec.varargs or argspec.keywords:
return False
if 1 == len(argspec.args):
return True
return False
raise RuntimeError('This line should not be reached')
您可以使用*args
参数控制与varargs参数**kwargs
和ignore_varargs
相关的行为。
typical_argument
参数是一个kludge:如果inspect
无效,例如在上述内置函数中,我们只是尝试用一个参数调用函数,看看会发生什么。
这种方法的问题在于raise TypeError
有多种原因:使用了错误数量的参数,或者使用了错误的参数类型。通过允许用户提供typical_argument
我试图绕过这个问题。
这不太好。但它可能会帮助人们有同样的问题,并且还会遇到inspect
无法检查C编码函数实现的事实。也许人们有更好的建议?