В чем разница между "append" и "+" в python?

Я не знаю, в чем разница между f() и g().

В функции f список L накапливается всякий раз, когда вызывается функция.

но в функции g это не..

def f(a, L=[]):
    L.append([2]);
    print(L);

def g(a, L=[]):
    L = L+[2];
    print(L);

print("f:")
f(1) # [[2]]
f(2) # [[2], [2]]
f(3) # [[2], [2], [2]]

print("g:")
g(1) # [2]
g(2) # [2]
g(3) # [2]
9
10 авг. '18 в 10:09
источник поделиться
6 ответов

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

Это связано с тем, что вы назначили список как значение по умолчанию для параметра функции, и вы назначаете результат конкатенации в локальной переменной в g.


Это не так широко известно, но определение списка (или dict или объекта) в качестве значения по умолчанию параметра, вероятно, не является тем, что вы хотите. Когда вы это сделаете, список, используемый в качестве значения по умолчанию для параметра, используется для всех вызовов функций.

Итак, для функции f:

  1. вы вызываете его в первый раз без параметра L, значение по умолчанию ([]) берется и добавляется с помощью 2. Таким образом, становится [2]
  2. вы вызываете его второй раз без параметра L, значение по умолчанию берется, но теперь оно [2]. 2 добавляется снова, и он становится [2, 2] который теперь является значением по умолчанию вашей функции.

для g функции:

  • как и для функции f, значением по умолчанию является пустой список, но этот список никогда не изменяется. Фактически результат L + [2] влияет на локальную переменную L а значение по умолчанию функции остается неизменным. Поэтому, когда вы снова вызываете функцию, значение по умолчанию всегда [].
  • Как сказал Клименкомуд в своем ответе, используя оператор += вместо конкатенации, и присваивание фактически изменяет значение по умолчанию параметра L Если вы это сделаете, функция g будет вести себя как функция f.

Как вывод, использование пустого списка в качестве значения по умолчанию для параметра почти никогда не является тем, что вы хотите. Вместо этого вы, вероятно, захотите этого:

def f(a, L=None):
    L = L or []
    ...
9
10 авг. '18 в 10:40
источник

В первой функции вы обновляете существующий list, добавляя в конец списка новые значения.

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

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

Например, попробуйте обновить код функции g до следующего:

def g(a, L=[]):
    L += [2]
    print(L)

Там вы увидите, что L тоже накоплен, как и в функции f, потому что здесь вы не переназначаете значение, а обновляете существующую переменную.

3
10 авг. '18 в 10:15
источник

Приложение добавляет элемент в конец списка. Поэтому, если вначале список L = [], то L.append([2]) добавит список элементов в исходный список L. Если вы снова сделаете L.append([3]), он добавит еще один сингл список элементов в конец исходного списка L. Ваш список L теперь фактически является списком списков.

+ - оператор конкатенации. Он объединяет два списка, как будто он объединяет две строки. Кроме того, имейте в виду, что оператор + всегда будет возвращать новый список с присоединенными элементами. Вот почему ваш список не растет, когда вы используете оператор+. Если вы хотите изменить существующий список, вы можете использовать функцию extend. Следующий ответ и комментарии сделают вам более понятным:

Разница между методами добавления и расширения списка в Python

Надеюсь, это поможет.

Изменить. Чтобы показать, как каждый каждый раз возвращает новый список, здесь приведен модифицированный код, который распечатывает идентификатор списка каждый раз, когда он печатает список:

def f(a, L=[]):
    L.append([2]);
    print(L);
    print(id(L))

def g(a, L=[]):
    #The following statement will print the id of default L
    print(id(L))
    L = L+[2];
    #The following statement will print the id of a new L stored in a diff location. The default L isnt modified.
    print(L);
    print(id(L))

f:
[[2]]
2354851792712
[[2], [2]]
2354851792712
[[2], [2], [2]]
2354851792712
g:
2354851792968
[2]
2354851791944
2354851792968
[2]
2354851791816
2354851792968
[2]
2354851792328

Как вы видите выше, каждый раз, когда вы добавляете, вы используете тот же список по умолчанию (2354851792712). Следовательно, ваш список растет. С другой стороны, использование + возвращает новый список и сохраняет его в новом месте вместо изменения местоположения по умолчанию L (2354851792968). Следовательно, он не растет.

2
10 авг. '18 в 10:21
источник

Это очень хорошо объясняет первую часть вашего вопроса: https://docs.quantifiedcode.com/python-anti-patterns/correctness/mutable_default_value_as_argument.html

Так как у вас есть изменяемый аргумент по умолчанию, python создаст его только один и передаст его каждому новому вызову функции.

Это объясняет поведение функции f. Для функции g вы должны учитывать, что оператор + создает новый список, который будет привязан к имени L Первоначальный список по умолчанию, который будет передан каждому вызову функции, не будет затронут (в функции f вы меняете сам объект).

Изменение: нашел эту ссылку: http://effbot.org/zone/default-values.htm Это объясняет поведение действительно хорошо. Таким образом, def является исполняемым и поэтому аргументы по умолчанию вычисляются в определении функции. Аргументы по умолчанию затем сохраняются в function.func_defaults. Во время вызова функции параметр по умолчанию передается из function.func_defaults в локальное имя L

1
10 авг. '18 в 10:32
источник
list.append(element)

добавляет "элемент" в список. Он не различает на основе типа данных "элемент".

Оператор конкатенации "+", хотя, похоже, выполняет ту же операцию, он объединяет одни и те же типы данных. Таким образом, вы можете объединять только списки списков. У вас не может быть list1+"string". Но вы можете иметь list1+["string1"], list1.append("string1") и list1.append(["string1"]).

Вопреки распространенному мнению, в python списки не являются неизменяемыми (изменяемыми). Это означает, что один и тот же объект можно редактировать снова и снова без изменения его ссылки. Однако кортежи и строки неизменяемы. Это означает, что новый объект создается всякий раз, когда вы редактируете кортеж или строку. Старая строка/кортеж затем отбрасывается системой сбора мусора.

1
10 авг. '18 в 10:31
источник

Вы используете изменяемое значение по умолчанию. При первом вызове f() или g() интерпретатор создает постоянный список. С append в f() вы изменяете этот список. Оператор + в g() вызывает создание нового объекта списка, поэтому постоянный объект списка, созданный для значения по умолчанию, остается нетронутым. Используйте id(L) чтобы распечатать ссылку на объекты, чтобы получить более глубокое понимание.

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

Обновить

Попробуйте запустить этот код, и вы увидите, что L имеет новый идентификатор после назначения результата операции + и больше не указывает на постоянный объект значения по умолчанию (он остался неизменным).

def a(new_element, L=[]):
    print(id(L))
    L = L + [new_element]
    print(id(L))

a(1)
1
10 авг. '18 в 10:29
источник

Посмотрите другие вопросы по метке или Задайте вопрос