Python обязательный список произвольных аргументов * args - PullRequest
0 голосов
/ 01 августа 2011

есть ли способ определить обязательные * аргументы (произвольные аргументы) в методе класса?

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

Учитывая это, вы можете создать объект из класса foo без каких-либо аргументов x = foo (), т. Е. Его необязательно. Любые идеи, как изменить его на необязательный или «дать мне хотя бы один аргумент» - что-нибудь?

Еще один вопрос касается распаковки списка с помощью x = foo (* list) -> Есть ли способ распознать список как список и автоматически распаковать список, чтобы вам не приходилось использовать * в вызов функции / метода?

Thx

Ответы [ 3 ]

4 голосов
/ 01 августа 2011

*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 пожалуйста, не задавайте более одного вопроса одновременно!

2 голосов
/ 01 августа 2011

Либо проверьте длину результирующего кортежа, либо поместите один или несколько нормальных аргументов перед ним.

номер

0 голосов
/ 01 августа 2011

Для "дайте мне хотя бы один аргумент" просто отметьте 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])

...