No Python, qual é a diferença entre ".append ()" e "+ = []"?

Respostas:

159

Para o seu caso, a única diferença é o desempenho: o acréscimo é duas vezes mais rápido.

Python 3.0 (r30:67507, Dec  3 2008, 20:14:27) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.Timer('s.append("something")', 's = []').timeit()
0.20177424499999999
>>> timeit.Timer('s += ["something"]', 's = []').timeit()
0.41192320500000079

Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.Timer('s.append("something")', 's = []').timeit()
0.23079359499999999
>>> timeit.Timer('s += ["something"]', 's = []').timeit()
0.44208112500000141

Em geral append, o item adiciona um item à lista, enquanto +=copia todos os elementos da lista do lado direito para a lista do lado esquerdo.

Atualização: análise perf

Comparando bytecodes, podemos assumir que a appendversão desperdiça ciclos em LOAD_ATTR+ CALL_FUNCTIONe + = version-in BUILD_LIST. Aparentemente BUILD_LISTsupera LOAD_ATTR+ CALL_FUNCTION.

>>> import dis
>>> dis.dis(compile("s = []; s.append('spam')", '', 'exec'))
  1           0 BUILD_LIST               0
              3 STORE_NAME               0 (s)
              6 LOAD_NAME                0 (s)
              9 LOAD_ATTR                1 (append)
             12 LOAD_CONST               0 ('spam')
             15 CALL_FUNCTION            1
             18 POP_TOP
             19 LOAD_CONST               1 (None)
             22 RETURN_VALUE
>>> dis.dis(compile("s = []; s += ['spam']", '', 'exec'))
  1           0 BUILD_LIST               0
              3 STORE_NAME               0 (s)
              6 LOAD_NAME                0 (s)
              9 LOAD_CONST               0 ('spam')
             12 BUILD_LIST               1
             15 INPLACE_ADD
             16 STORE_NAME               0 (s)
             19 LOAD_CONST               1 (None)
             22 RETURN_VALUE

Podemos melhorar ainda mais o desempenho removendo a LOAD_ATTRsobrecarga:

>>> timeit.Timer('a("something")', 's = []; a = s.append').timeit()
0.15924410999923566
Constantin
fonte
12
+1: Isso é muito interessante. Eu uso o anexo de qualquer maneira, porque resulta em um código mais claro. Mas não percebi que havia uma diferença de desempenho. Se alguma coisa, eu esperava que o apêndice fosse mais lento, pois é uma chamada de função garantida, enquanto eu presumi que + = seria otimizado ainda mais.
DNS
2
Também não há uma diferença funcional? Por exemplo, deixe a = [] , b = [4,5,6] , aqui se você fizer c = a.append (b), então c seria uma lista da lista [[4,5,6]] enquanto c + = b ; levaria a uma lista simples c = [4,5,6] .
Rph 04/07/19
apenas para esclarecer as coisas: + = oferece um desempenho melhor do que estender ou acrescentar, desde que sua entrada esteja no formato correto. O que leva tempo no exemplo atual é a criação da lista ['something']. + = É de cerca de 15% mais rápido
Joe
@ Joe Se você está comparando appendvs +=, deve incluir a criação da lista como parte da medição. Caso contrário, seria uma pergunta diferente ( extendvs +=).
jamesdlin
@jamesdlin yup! Mas é fácil ser enganado, a menos que você já saiba disso. Um pouco de precisão adicional nunca prejudicou ninguém, certo?
Joe
47

No exemplo que você deu, não há diferença, em termos de saída, entre appende +=. Mas há uma diferença entre appende +(sobre o qual a pergunta originalmente foi feita).

>>> a = []
>>> id(a)
11814312
>>> a.append("hello")
>>> id(a)
11814312

>>> b = []
>>> id(b)
11828720
>>> c = b + ["hello"]
>>> id(c)
11833752
>>> b += ["hello"]
>>> id(b)
11828720

Como você pode ver, appende +=tenha o mesmo resultado; eles adicionam o item à lista, sem produzir uma nova lista. Usar +adiciona as duas listas e produz uma nova lista.

DNS
fonte
Não é diferença entre acréscimo e + =.
Constantin
3
Há o fato de appendadicionar uma entrada à lista, enquanto + = adiciona quantas houver na outra lista (ou seja, aliases para extend). Mas ele / ela já sabe disso, julgando pela forma como a pergunta foi escrita. Há alguma outra diferença que estou perdendo?
DNS
1
Há uma diferença porque uma tarefa aumentada introduz a religação (explicação na minha resposta).
9990
42
>>> a=[]
>>> a.append([1,2])
>>> a
[[1, 2]]
>>> a=[]
>>> a+=[1,2]
>>> a
[1, 2]

Veja que o apêndice adiciona um único elemento à lista, que pode ser qualquer coisa. +=[]junta-se às listas.

dwc
fonte
2
Votação, porque esta é uma distinção importante entre os dois. Bom trabalho.
31

+ = é uma tarefa. Quando você o usa, está realmente dizendo 'some_list2 = some_list2 + [' something ']'. As atribuições envolvem religação, portanto:

l= []

def a1(x):
    l.append(x) # works

def a2(x):
    l= l+[x] # assign to l, makes l local
             # so attempt to read l for addition gives UnboundLocalError

def a3(x):
    l+= [x]  # fails for the same reason

O operador + = também deve normalmente criar um novo objeto de lista como list + list normalmente:

>>> l1= []
>>> l2= l1

>>> l1.append('x')
>>> l1 is l2
True

>>> l1= l1+['x']
>>> l1 is l2
False

No entanto, na realidade:

>>> l2= l1
>>> l1+= ['x']
>>> l1 is l2
True

Isso ocorre porque as listas Python implementam __iadd __ () para criar um curto-circuito na atribuição aumentada + = e chamar list.extend (). (É uma verruga estranha: isso geralmente faz o que você quis dizer, mas por razões confusas.)

Em geral, se você estiver anexando / estendendo uma lista existente e quiser manter a referência à mesma lista (em vez de criar uma nova), é melhor ser explícito e seguir o append () / extend () métodos.

bobince
fonte
21
 some_list2 += ["something"]

é na verdade

 some_list2.extend(["something"])

para um valor, não há diferença. A documentação declara que:

s.append(x) o mesmo s[len(s):len(s)] = [x]
s.extend(x) que os[len(s):len(s)] = x

Portanto, obviamente, s.append(x)é o mesmo ques.extend([x])

vartec
fonte
s.append pega um tipo arbitrário e o adiciona à lista; É um verdadeiro anexo. s.extend pega um iterável (geralmente uma lista) e funde o iterável em s, modificando os endereços de memória de s. Estes não são os mesmos.
W4t3randWind 31/03
9

A diferença é que concatenar achatará a lista resultante, enquanto o apêndice manterá os níveis intactos:

Então, por exemplo, com:

myList = [ ]
listA = [1,2,3]
listB = ["a","b","c"]

Usando o anexo, você acaba com uma lista de listas:

>> myList.append(listA)
>> myList.append(listB)
>> myList
[[1,2,3],['a',b','c']]

Usando concatenar, você acaba com uma lista simples:

>> myList += listA + listB
>> myList
[1,2,3,"a","b","c"]
SRC2
fonte
5

Os testes de desempenho aqui não estão corretos:

  1. Você não deve executar o perfil apenas uma vez.
  2. Se comparar o apêndice vs. + = [] número de vezes, você deve declarar o apêndice como uma função local.
  3. os resultados de tempo são diferentes nas diferentes versões do python: 64 e 32 bits

por exemplo

timeit.Timer ('para i no xrange (100): app (i)', 's = []; app = s.append'). timeit ()

bons testes podem ser encontrados aqui: http://markandclick.com/1/post/2012/01/python-list-append-vs.html

Michael
fonte
ainda assim, os testes + = nessa página são usados += [one_var]. Se omitirmos a criação de listas, + = se torna a opção mais rápida.
Joe
3

Além dos aspectos descritos nas outras respostas, anexar e + [] têm comportamentos muito diferentes quando você está tentando criar uma lista de listas.

>>> list1=[[1,2],[3,4]]
>>> list2=[5,6]
>>> list3=list1+list2
>>> list3
[[1, 2], [3, 4], 5, 6]
>>> list1.append(list2)
>>> list1
[[1, 2], [3, 4], [5, 6]]

list1 + ['5', '6'] adiciona '5' e '6' à lista1 como elementos individuais. list1.append (['5', '6']) adiciona a lista ['5', '6'] à lista1 como um único elemento.

Chris Upchurch
fonte
2

O comportamento de religação mencionado em outras respostas é importante em determinadas circunstâncias:

>>> a = ([],[])
>>> a[0].append(1)
>>> a
([1], [])
>>> a[1] += [1]
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Isso ocorre porque as atribuições aumentadas sempre são religadas, mesmo que o objeto tenha sido alterado no local. A religação aqui acontece a[1] = *mutated list*, o que não funciona para tuplas.

Restabelecer Monica
fonte
0

vamos dar um exemplo primeiro

list1=[1,2,3,4]
list2=list1     (that means they points to same object)

if we do 
list1=list1+[5]    it will create a new object of list
print(list1)       output [1,2,3,4,5] 
print(list2)       output [1,2,3,4]

but if we append  then 
list1.append(5)     no new object of list created
print(list1)       output [1,2,3,4,5] 
print(list2)       output [1,2,3,4,5]

extend(list) also do the same work as append it just append a list instead of a 
single variable 
Avnish kumar
fonte
0

O método append () adiciona um único item à lista existente

some_list1 = []
some_list1.append("something")

Então aqui o some_list1 será modificado.

Atualizada:

Enquanto usar + para combinar os elementos das listas (mais de um elemento) na lista existente, semelhante à extensão (conforme corrigida pelo Flux ).

some_list2 = []
some_list2 += ["something"]

Então aqui a some_list2 e ["something"] são as duas listas que são combinadas.

Naveen Verma
fonte
1
Isto está errado. +=não retorna uma nova lista. O FAQ de programação diz: "... para listas, __iadd__é equivalente a entrar extendna lista e retornar a lista. É por isso que dizemos que para listas, +=é um" atalho "para list.extend". Você também pode ver isso no código fonte do CPython: github.com/python/cpython/blob/v3.8.2/Objects/…
Flux
0

"+" não altera a lista

.append () modifica a lista antiga

Andres
fonte