Se tomarmos b = [1,2,3]
e se tentarmos:b+=(4,)
Ele retorna b = [1,2,3,4]
, mas se tentarmos fazer b = b + (4,)
isso não funcionará.
b = [1,2,3]
b+=(4,) # Prints out b = [1,2,3,4]
b = b + (4,) # Gives an error saying you can't add tuples and lists
Eu esperava b+=(4,)
falhar, pois você não pode adicionar uma lista e uma tupla, mas funcionou. Por isso, tentei b = b + (4,)
obter o mesmo resultado, mas não funcionou.
python
python-3.x
list
tuples
Supun Dasantha Kuruppu
fonte
fonte
Respostas:
O problema das perguntas "por que" é que geralmente elas podem significar várias coisas diferentes. Vou tentar responder a cada uma que acho que você possa ter em mente.
"Por que é possível funcionar de maneira diferente?" o que é respondido por, por exemplo, isto . Basicamente,
+=
tenta usar métodos diferentes do objeto:__iadd__
(que só é verificado no lado esquerdo), vs__add__
e__radd__
("reverse reverse"), verificado no lado direito se o lado esquerdo não tiver__add__
) para+
."O que exatamente cada versão faz?" Em resumo, o
list.__iadd__
método faz a mesma coisa quelist.extend
(mas, devido ao design da linguagem, ainda há uma atribuição de volta).Isso também significa, por exemplo, que
+
, é claro, cria um novo objeto, mas requer explicitamente outra lista em vez de tentar extrair elementos de uma sequência diferente."Por que é útil + = fazer isso? É mais eficiente; o
extend
método não precisa criar um novo objeto. É claro que isso tem alguns efeitos surpreendentes às vezes (como acima), e geralmente o Python não é realmente sobre eficiência , mas essas decisões foram tomadas há muito tempo."Qual é o motivo para não permitir adicionar listas e tuplas com +?" Veja aqui (obrigado, @ splash58); Uma ideia é que (tupla + lista) produza o mesmo tipo que (lista + tupla) e não está claro qual o tipo de resultado.
+=
não tem esse problema, porquea += b
obviamente não deve alterar o tipo dea
.fonte
|
, então isso meio que arruina meu exemplo. Se eu pensar em um exemplo mais claro mais tarde, eu o troco.|
para conjuntos é um operador pendulares, mas+
para listas não é. Por esse motivo, não acho que o argumento sobre a ambiguidade de tipo seja particularmente forte. Como o operador não comuta, por que exigir o mesmo para os tipos? Pode-se apenas concordar que o resultado tem o tipo de lhs. Por outro lado, ao restringirlist + iterator
, o desenvolvedor é incentivado a ser mais explícito sobre suas intenções. Se você deseja criar uma nova lista que contém o material a partira
prorrogado pelo material dob
já existe uma maneira de fazer isso:new = a.copy(); new += b
. É mais uma linha, mas cristalina.a += b
se comporta de maneira diferente do quea = a + b
não é eficiência. Na verdade, Guido considerou o comportamento escolhido menos confuso. Imagine uma função recebendo uma listaa
como argumento e depois fazendoa += [1, 2, 3]
. Essa sintaxe certamente parece estar modificando a lista no lugar, em vez de criar uma nova lista; portanto, foi tomada a decisão de que ela deveria se comportar de acordo com a intuição da maioria das pessoas sobre o resultado esperado. No entanto, o mecanismo também teve que trabalhar para tipos imutáveis comoint
s, o que levou ao design atual.a += b
abreviara = a + b
, como Ruby fez, mas posso entender como chegamos lá.Eles não são equivalentes:
é uma abreviação de:
enquanto
+
concatena listas, portanto:você está tentando concatenar uma tupla para uma lista
fonte
Quando você faz isso:
é convertido para isso:
Sob o capô que ele chama
b.extend((4,))
,extend
aceita um iterador e é por isso que isso também funciona:mas quando você faz isso:
é convertido para isso:
aceite apenas objeto de lista.
fonte
Nos documentos oficiais, para os tipos de sequência mutável, ambos:
são definidos como:
O que é diferente de ser definido como:
Isso também significa que qualquer tipo de sequência funcionará
t
, incluindo uma tupla como no seu exemplo.Mas também funciona para gamas e geradores! Por exemplo, você também pode fazer:
fonte
Os operadores de atribuição "aumentada", como
+=
foram introduzidos no Python 2.0, lançado em outubro de 2000. O design e a lógica estão descritos no PEP 203 . Um dos objetivos declarados desses operadores era o suporte às operações no local. Escritadeve atualizar a lista
a
no local . Isso importa se houver outras referências à listaa
, por exemplo, quandoa
foi recebido como argumento de função.No entanto, a operação nem sempre pode acontecer no local, pois muitos tipos de Python, incluindo números inteiros e seqüências de caracteres, são imutáveis , portanto, por exemplo,
i += 1
para um número inteiroi
não é possível operar no local.Em resumo, os operadores de atribuição aumentada deveriam trabalhar no local quando possível e criar um novo objeto de outra forma. Para facilitar esses objetivos de design, a expressão
x += y
foi especificada para se comportar da seguinte maneira:x.__iadd__
definido,x.__iadd__(y)
é avaliado.x.__add__
implementado,x.__add__(y)
é avaliado.y.__radd__
implementado,y.__radd__(x)
é avaliado.O primeiro resultado obtido por esse processo será atribuído de volta a
x
(a menos que esse resultado seja oNotImplemented
singleton, nesse caso a pesquisa continua com a próxima etapa).Esse processo permite que tipos que suportam modificações no local sejam implementados
__iadd__()
. Tipos que não suportam modificação no local não precisam adicionar novos métodos mágicos, já que o Python volta automaticamente ao essencialx = x + y
.Então, finalmente, vamos à sua pergunta real - por que você pode adicionar uma tupla a uma lista com um operador de atribuição aumentada. De memória, o histórico disso era mais ou menos assim: O
list.__iadd__()
método foi implementado para simplesmente chamar olist.extend()
método já existente no Python 2.0. Quando os iteradores foram introduzidos no Python 2.1, olist.extend()
método foi atualizado para aceitar iteradores arbitrários. O resultado final dessas mudanças foi o quemy_list += my_tuple
funcionou a partir do Python 2.1. Olist.__add__()
método, no entanto, nunca deveria suportar iteradores arbitrários como o argumento da direita - isso foi considerado inadequado para uma linguagem fortemente tipada.Pessoalmente, acho que a implementação de operadores aumentados acabou sendo um pouco complexa em Python. Tem muitos efeitos colaterais surpreendentes, por exemplo, este código:
A segunda linha aumenta
TypeError: 'tuple' object does not support item assignment
, mas a operação é executada com êxito de qualquer maneira -t
será([42, 44], [43])
após a execução da linha que gera o erro.fonte
A maioria das pessoas espera que X + = Y seja equivalente a X = X + Y. De fato, o Python Pocket Reference (4ª ed) de Mark Lutz diz na página 57 "Os dois formatos a seguir são aproximadamente equivalentes: X = X + Y, X + = Y ". No entanto, as pessoas que especificaram o Python não os tornaram equivalentes. Possivelmente, esse foi um erro que resultará em horas de tempo de depuração por programadores frustrados enquanto o Python permanecer em uso, mas agora é exatamente como o Python é. Se X é um tipo de sequência mutável, X + = Y é equivalente a X.extend (Y) e não a X = X + Y.
fonte
Como é explicado aqui , se
array
não implementar o__iadd__
método,b+=(4,)
isso seria apenas um atalho,b = b + (4,)
mas obviamente não é, o mesmoarray
acontece com o__iadd__
método. Aparentemente, a implementação do__iadd__
método é algo como isto:No entanto, sabemos que o código acima não é a implementação real do
__iadd__
método, mas podemos assumir e aceitar que existe algo como oextend
método, que aceitatupple
entradas.fonte