Подтвердить что ты не робот

Распаковка более одного списка в качестве аргумента для функции

Если у меня есть функция вроде:

def f(a,b,c,d):
    print a,b,c,d

Тогда почему это работает:

f(1,2,3,4)
f(*[1,2,3,4])

Но не это:

f(*[1,2] , *[3,4])
    f(*[1,2] , *[3,4])
               ^
SyntaxError: invalid syntax

?

EDIT: Для информации исходная проблема заключалась в замене одного из аргументов в оболочке функции. Я хотел заменить данный член введенных * args и попробовал что-то вроде:

def vectorize_pos(f,n=0):
    '''
    Decorator, vectorize the processing of the nth argument
    :param f: function that dont accept a list as nth argument
    '''
    def vectorizedFunction(*args,**kwargs):
        if isinstance(args[n],list):
            return map(lambda x : f( *(args[:n]) , x , *(args[n+1,:]), **kwargs),args[n])
        else:
            return f(*args,**kwargs)
    return vectorizedFunction

То, откуда возник вопрос. И я знаю, что есть другой способ сделать то же самое, но только хотел понять, почему распаковка одной последовательности сработала, но не для большего.

4b9b3361

Ответ 1

Поскольку в соответствии с синтаксисом вызова функций, так определяется список аргументов

argument_list ::=  positional_arguments ["," keyword_arguments]
                     ["," "*" expression] ["," keyword_arguments]
                     ["," "**" expression]
                   | keyword_arguments ["," "*" expression]
                     ["," keyword_arguments] ["," "**" expression]
                   | "*" expression ["," keyword_arguments] ["," "**" expression]
                   | "**" expression

Таким образом, вы можете передать только один * expression для вызова функции.

Ответ 2

Начиная с Python 3.5, этот работает .

PEP 448 был реализован в Python 3.5. Цитируя из PEP, он позволяет, среди прочего:

Произвольно упорядоченные операторы распаковки:

>>> print(*[1], *[2], 3)
1 2 3
>>> dict(**{'x': 1}, y=2, **{'z': 3})
{'x': 1, 'y': 2, 'z': 3}

Ответ 3

Вы можете объединить списки:

>>> f(*[1,2]+[3,4])
1 2 3 4

или используйте itertools.chain:

>>> from itertools import chain
>>> f(*chain([1,2], [3,4]))
1 2 3 4

Ответ 4

Это будет работать.

>>>def f(a,b,c,d):
         print('hello') #or whatever you wanna do. 
>>>f(1,2,*[3,4])
hello

Причина, по которой это не получается, заключается в том, что Python реализует это с помощью this

Один список распаковывается и, следуя семантике, любой аргумент после этого должен быть именованным аргументом ключевого слова (или профайлом, передающим именованные аргументы ключевого слова через **)

По контрасту это сработает.

>>>def f(a,b,c,k):
       pass
>>>f(1,*[2,3],k=4)

Ответ 5

Это не работает, потому что это недействительный синтаксис, то есть на самом деле это не Python, хотя он выглядит так.

В сигнатурах функций Python 2 разрешен только один отмеченный параметр, и он должен следовать любым позиционным параметрам и предшествовать любым параметрам ключевых слов. Аналогично допускается только один аргумент с двумя звездочками, и он должен следовать за всеми параметрами ключевого слова в сигнатуре. Если у вас есть несколько списков аргументов, которые вы хотели бы отправить, вам действительно придется сначала создать из них один список.

В Python 3 также можно использовать звезду самостоятельно, чтобы указать, что любые следующие параметры являются так называемыми параметрами только для ключевого слова, но я не думаю, что нам нужно только в это время.

Ответ 6

* здесь не действует как оператор. Это больше похоже на часть синтаксиса вызовов функций, и это позволяет только ограниченные возможности. Было бы возможно определить язык, чтобы вы могли делать то, что хотите (я это сделал!), Но это был не тот выбор, который был сделан.

Ответ 7

Это может помочь. Обратите внимание, что аналогия - это переменное количество аргументов на других языках. Это означает, что, как только вы скажете, что собираетесь использовать переменное количество аргументов, все следующие аргументы являются частью этого списка (аналогия с использованием varargs на C или С++).

например   f = [1,2,3,4,5]

def func(a, b, c, d)
  print a, b, c, d

func(f) # Error 1 argument, 4 required

func(*f) # Error 5 arguments 4 required

http://www.python-course.eu/passing_arguments.php

Переменная длина параметров
Введем теперь функции, которые может принимать произвольное количество аргументов. Те, у кого есть программирование фона на C или С++ знает об этом из функции varargs этих языков. Звездочка "*" используется в Python для определения переменное количество аргументов. Символ звездочки должен предшествовать Идентификатор переменной в списке параметров.

>>> def varpafu(*x): print(x)
... 
>>> varpafu()
()
>>> varpafu(34,"Do you like Python?", "Of course")
(34, 'Do you like Python?', 'Of course')
>>> 

Из предыдущего примера мы узнаем, что аргументы, переданные вызов функции varpafu() собираются в кортеже, что может быть доступ как "нормальная" переменная x внутри тела функции. Если функция вызывается без каких-либо аргументов, значение x является пустой кортеж.

Иногда необходимо использовать позиционные параметры, за которыми следует произвольное количество параметров в определении функции. Это возможно, но позиционные параметры всегда должны предшествовать произвольные параметры. В следующем примере у нас есть позиционный параметр "город", - основное место, - которое всегда должно быть а затем произвольное количество других мест:

>>> def locations(city, *other_cities): print(city, other_cities)
... 
>>> locations("Paris")
('Paris', ())
>>> locations("Paris", "Strasbourg", "Lyon", "Dijon", "Bordeaux", "Marseille")
('Paris', ('Strasbourg', 'Lyon', 'Dijon', 'Bordeaux', 'Marseille'))
>>>

http://docs.python.org/2.7/reference/expressions.html

Если выражение функции синтаксиса * появляется в вызове функции, выражение должен оцениваться итерабельным. Элементы из этого итерабельного обрабатываются как если бы они были дополнительными позиционными аргументами; если есть позиционные аргументы x1,..., xN и выражение оцениваются как последовательность y1,..., yM, это эквивалентно вызову с позицией M + N аргументы x1,..., xN, y1,..., yM.

Следствием этого является то, что хотя синтаксис выражения * появляются после некоторых аргументов ключевого слова, они обрабатываются до аргументы ключевого слова (и аргумент выражения **, если есть - см. ниже). Итак:

  <Р →   
>>> def f(a, b): ...  print a, b ...
>>> f(b=1, *(2,)) 2 1
>>> f(a=1, *(2,)) Traceback (most recent call last):   File "<stdin>", line 1, in ? TypeError: f() got multiple values for keyword argument
'a'
>>> f(1, *(2,)) 1 2

Это необычно для обоих аргументов ключевого слова и синтаксиса выражения * можно использовать в одном и том же вызове, поэтому на практике эта путаница не возникают.

Если выражение функции синтаксиса ** появляется в вызове функции, выражение должны оцениваться до отображения, содержание которого трактуется как дополнительные аргументы ключевых слов. В случае появления ключевого слова в оба выражения и как явный аргумент ключевого слова, TypeError исключение.