Python mandatoryl任意参数列表* args

时间:2011-07-31 22:55:29

标签: python variadic-functions

有没有办法在类的方法中定义强制* args(任意参数)?

class foo():
 def __init__(self,*args):
      ....

鉴于此,你可以从foo-class创建一个对象而不需要任何参数x = foo(),即它是可选的。任何想法如何将其改为非可选或“给我至少一个参数” - 一切?

另一个问题涉及使用x = foo(* list)解压缩列表 - >有没有办法将列表识别为列表并自动解压缩列表,这样您就不必在函数/方法调用中使用*?

THX

3 个答案:

答案 0 :(得分:4)

*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 请不要一次提出多个问题!

答案 1 :(得分:2)

测试结果元组的长度,或者在它之前加上一个或多个普通参数。

没有

答案 2 :(得分:0)

对于“至少给我一个参数”,只需检查你收到的元组的len(),如果你没有得到至少一个则抛出异常。在这里,我使用的事实是空元组是“虚假的”来隐含地这样做:

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])