Python 强制性任意参数列表 *args
有没有办法在一个类的方法中定义一个必须要传的 *args(任意参数)呢?
class foo():
def __init__(self,*args):
....
根据这个,你可以创建一个 foo 类的对象,而不需要传任何参数,比如 x=foo(),也就是说这个参数是可选的。有没有什么办法可以把它改成一个非可选的,或者说“至少给我一个参数”的形式呢?
另一个问题是关于列表解包的,像 x=foo(*list) 这样——有没有办法让这个列表被识别为列表,并且自动解包,这样在调用函数或方法的时候就不需要使用 * 了?
谢谢
3 个回答
对于“至少给我一个参数”,你只需要检查一下收到的元组的长度,如果没有至少一个,就抛出一个异常。在这里,我利用了空元组被认为是“假”的这个特性,来隐式地做到这一点:
def __init__(self, *args):
if not args:
raise TypeError("__init__ takes at least 2 arguments (1 given)")
至于“自动解包”,你也需要自己进行测试并实现这个功能。一种方法可能是:
if len(args) == 1 and not isinstance(args[0], basestring) and iter(args[0]):
args = args[0]
使用iter()
时,它总是会返回真,但如果你传入的东西不是可迭代的,就会抛出一个异常。如果你想提供一个更友好的错误信息,可以捕捉这个异常,然后抛出其他的异常。
另一种选择是写一个方法,让它递归地遍历args
中的所有元素以及其中的所有子容器;这样就没关系了。
或者,你也可以让调用者一开始就传入一个可迭代的对象,这样就不用去处理*args
了。如果调用者想传入一个单独的项目,可以使用简单的语法把它变成一个列表:foo([item])
要么检查一下得到的元组的长度,要么在它前面加一个或多个普通的参数。
不。
*args
是用来接收所有那些没有被普通参数占用的参数。
通常,如果你想要一个参数是必须的,你只需要用一个普通参数就可以了:
>>> def foo(arg, *rest):
... print arg, rest
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes at least 1 argument (0 given)
如果你觉得把所有参数放在一个元组里更优雅,那你就得自己处理错误的情况:
>>> def foo(*args):
... if len(args) < 1:
... raise TypeError('foo() takes at least 1 argument (%i given)' % len(args))
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in foo
TypeError: foo() takes at least 1 argument (0 given)
但是从这个函数的定义来看,使用这个函数的人并不清楚有多少个参数是必须的。你应该尽量避免这种情况,或者至少要把它写得非常清楚。
还有其他问题:如果你给 foo()
传一个可迭代的参数(比如字符串),你可能得不到想要的结果。
回应你下面的评论,你的第一种方法是对的:使用一个列表。
def scrape(urls):
for url in urls:
do_something(url)
调用者只需要传一个只有一个元素的列表:scrape(['localhost'])
。
更好的做法可能是只接受一个 URL,让调用者自己遍历列表。这样的话,调用者如果想的话,可以并行处理这些操作。
至于你的第二个问题1:你的函数要么接受一个列表作为参数,要么不接受。要么在你的程序中传递列表是有意义的,要么没有意义。
我想,我不太确定你在问什么,但你的整个问题听起来像是你发现了一个新玩意儿,现在想到处用它,不管它是否合适。
1 请不要一次问多个问题!