кортежи как аргументы функции - PullRequest
3 голосов
/ 07 июня 2019

a tuple в python (в блоке кода) определяется запятыми;круглые скобки не являются обязательными (в случаях ниже).так что все эти три эквивалентны:

a, b = 1, 2
a, b = (1, 2)
(a, b) = 1, 2

, если я определю функцию

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

, вызов ее таким образом будет работать:

f(2, 3)

это не будет:

f((2, 3))
# TypeError: f() missing 1 required positional argument: 'b'

как python по-разному обрабатывает кортежи, когда они являются аргументами функции?здесь необходимы скобки (я понимаю , почему это так, и я счастлив, что Python работает таким образом!).

мой вопрос: как Python по-разному относится к кортежам, когда они функционируют?аргументы.

Ответы [ 3 ]

5 голосов
/ 07 июня 2019

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

Когда вы вызываете функцию, вы не предоставляете кортеж. Вы предоставляете аргументы. Кортеж может быть аргументом, но только одним - это просто переменная типа tuple.

Что вы можете сделать, это развернуть кортеж (или список) в серию аргументов с такой нотацией:

tup = (2, 3)
f(*tup)
# expand the tuple (2,3) into a series of arguments 2, 3

Вы можете сделать это и со словарями, кроме как с ** вместо *:

my_dict = {"arg1": 1, "arg2": 2}
f(arg1=my_dict["arg1"], arg2=my_dict["arg2"])
f(**my_dict)   # these are equivalent

С другой стороны, функции могут принимать произвольное количество аргументов (аналогично тому, как другие языки делают для вызовов printf()). Например:

def g(*args):
    print("I got this many arguments:", len(args))

Здесь, если вы делаете type(args), вы получаете tuple, а если вы делаете type(*args), вы получаете ошибку. Это связано с тем, что в заголовках функций * делает прямо противоположное: упаковывает аргументы, переданные функции, в один кортеж, чтобы вы могли работать с ними. Учтите следующее:

g(2, 3)  # 2 arguments, both integers
g((2, 3)) # 1 argument, a tuple
g(*(2, 3)) # 2 arguments, both integers

Короче говоря,

  • функции построены таким образом, что они принимают произвольное количество аргументов
  • Операторы * и ** могут распаковывать наборов / списков / диктов в аргументы на одном конце и упаковывать их на другом конце
  • отдельные кортежи / списки / дикты - это просто отдельные переменные.
3 голосов
/ 07 июня 2019

Дело в том, что в Python параны используются для нескольких разных вещей - для вызова функций, для создания кортежей (это не просто запятых, которые имеют значение, см. Пустой кортеж ()), дляизменение приоритета оценки в выражениях.

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

Если бы синтаксический анализатор Python был реализован так, чтобы он анализировал это как кортеж, было бы невозможно иметь функции с более чем одним аргументом.Если синтаксический анализатор Python был реализован так, что он анализировал это как два аргумента, невозможно передать буквальный кортеж без паренов.

Ясно, что первое является гораздо большим ограничением, поэтому был выбран второй.

Другой пример - с кортежами с one element - это (1+2) выражение с числом 3 или кортеж с одним элементом, 3?Здесь, если бы он был вторым, тогда было бы невозможно использовать парены для выражения приоритета в выражении ((3+4)*5 против 3+(4*5)).Поэтому было решено потребовать запятую после первого элемента для кортежей из 1 элемента ((3,)).

3 голосов
/ 07 июня 2019

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

Вызов функции не является оператором присваивания; это эталонное отображение. Следовательно, семантика различна.

Если вы хотите, чтобы Python распаковывал ваш кортеж в два отдельных аргумента, используйте оператор *:

f(*(2, 3))
...