Jeśli weźmiemy b = [1,2,3]
i spróbujemy:b+=(4,)
Zwraca b = [1,2,3,4]
, ale jeśli spróbujemy b = b + (4,)
to zrobić, to nie zadziała.
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
Spodziewałem b+=(4,)
się niepowodzenia, ponieważ nie można dodać listy i krotki, ale zadziałało. Próbowałem więc b = b + (4,)
oczekiwać takiego samego rezultatu, ale to nie zadziałało.
python
python-3.x
list
tuples
Supun Dasantha Kuruppu
źródło
źródło
Odpowiedzi:
Problem z pytaniami „dlaczego” polega na tym, że zwykle mogą oznaczać wiele różnych rzeczy. Postaram się odpowiedzieć na każde, o czym myślę, że masz na myśli.
„Dlaczego to może działać inaczej?” na co odpowiada np . ten . Zasadniczo
+=
próbuje użyć różnych metod obiektu:__iadd__
(który jest zaznaczony tylko po lewej stronie), vs__add__
i__radd__
(„dodaj wstecz”, zaznaczony po prawej stronie, jeśli strona po lewej nie ma__add__
) dla+
.„Co dokładnie robi każda wersja?” Krótko mówiąc,
list.__iadd__
metoda robi to samo colist.extend
(ale z powodu projektu językowego nadal istnieje przypisanie z powrotem).Oznacza to również na przykład, że
+
, oczywiście tworzy nowy obiekt, ale jawnie wymaga innej listy zamiast próbować wyciągać elementy z innej sekwencji.„Dlaczego warto to zrobić + = Jest to bardziej wydajne;
extend
metoda nie musi tworzyć nowego obiektu. Oczywiście ma to czasem zaskakujące efekty (jak wyżej), a generalnie Python tak naprawdę nie dotyczy wydajności , ale te decyzje zostały podjęte dawno temu.„Dlaczego nie zezwalam na dodawanie list i krotek za pomocą +?” Zobacz tutaj (dzięki, @ splash58); jednym z pomysłów jest to, że (krotka + lista) powinna dawać ten sam typ co (lista + krotka) i nie jest jasne, jaki typ powinien być wynik.
+=
nie ma tego problemu, ponieważa += b
oczywiście nie powinien zmieniać typua
.źródło
|
, więc to trochę rujnuje mój przykład. Jeśli później wymyślę wyraźniejszy przykład, zamienię go.|
dla zestawów jest operatorem dojeżdżającym, ale+
dla list nie jest. Z tego powodu nie sądzę, aby argument o niejednoznaczności typu był szczególnie silny. Ponieważ operator nie dojeżdża do pracy, dlaczego wymaga tego samego dla typów? Można po prostu zgodzić się, że wynik ma typ lhs. Z drugiej strony, ograniczająclist + iterator
, zachęca się programistę do wyraźniejszego wyrażenia swoich zamiarów. Jeśli chcesz utworzyć nową listę, która zawiera materiał za
udzielonych przez rzeczy zb
tam już sposobem, aby to zrobić:new = a.copy(); new += b
. To jeszcze jedna linia, ale krystalicznie czysta.a += b
zachowuje się inaczej niża = a + b
nie jest wydajność. W rzeczywistości Guido uznał, że wybrane zachowanie jest mniej mylące. Wyobraź sobie, że funkcja odbiera listęa
jako argument, a następnie robia += [1, 2, 3]
. Ta składnia z pewnością wygląda na to, że modyfikuje listę, zamiast tworzyć nową, więc zdecydowano, że powinna ona zachowywać się zgodnie z intuicją większości ludzi na temat oczekiwanego wyniku. Jednak mechanizm musiał również działać dla niezmiennych typów, takich jakint
s, co doprowadziło do obecnego projektu.a += b
skrótua = a + b
, jak to zrobiła Ruby, ale rozumiem, jak się tam dostaliśmy.Nie są równoważne:
jest skrótem od:
podczas
+
konkatenacji list, więc przez:próbujesz połączyć krotkę z listą
źródło
Kiedy to zrobisz:
jest konwertowany na to:
Pod maską woła
b.extend((4,))
,extend
akceptuje iterator i dlatego to również działa:ale kiedy to zrobisz:
jest konwertowany na to:
akceptuj tylko obiekt listy.
źródło
Z oficjalnych dokumentów, dla zmiennych typów sekwencji zarówno:
są zdefiniowane jako:
Który jest inny niż zdefiniowany jako:
Oznacza to również, że będzie działać dowolny typ sekwencji
t
, w tym krotka jak w twoim przykładzie.Ale działa również w przypadku zakresów i generatorów! Na przykład możesz także:
źródło
„Rozszerzone” operatory przypisania, takie jak,
+=
zostały wprowadzone w Pythonie 2.0, który został wydany w październiku 2000 r. Projekt i uzasadnienie opisano w PEP 203 . Jednym z deklarowanych celów tych operatorów było wsparcie operacji na miejscu. Pisaniema aktualizować listę
a
na miejscu . Ma to znaczenie, jeśli istnieją inne odwołania do listya
, np. Kiedya
otrzymano ją jako argument funkcji.Jednak operacja nie zawsze może mieć miejsce, ponieważ wiele typów Pythona, w tym liczby całkowite i łańcuchy, są niezmienne , więc np.
i += 1
Dla liczb całkowitychi
nie można operować w miejscu.Podsumowując, operatorzy rozszerzonego przypisania mieli działać, gdy to możliwe, i tworzyć nowy obiekt w inny sposób. Aby ułatwić osiągnięcie tych celów projektowych, określono wyrażenie, które
x += y
będzie zachowywać się w następujący sposób:x.__iadd__
jest zdefiniowane,x.__iadd__(y)
jest oceniane.x.__add__
jest implementowany,x.__add__(y)
jest oceniany.y.__radd__
jest implementowany,y.__radd__(x)
jest oceniany.Pierwszy wynik uzyskany w tym procesie zostanie przypisany z powrotem
x
(chyba że wynikiem jestNotImplemented
singleton, w którym to przypadku wyszukiwanie jest kontynuowane w następnym kroku).Ten proces pozwala na wdrożenie typów obsługujących modyfikacje w miejscu
__iadd__()
. Typy, które nie obsługują modyfikacji w miejscu, nie muszą dodawać żadnych nowych magicznych metod, ponieważ Python automatycznie do nich wrócix = x + y
.W końcu przejdźmy do twojego rzeczywistego pytania - dlaczego możesz dodać krotkę do listy za pomocą rozszerzonego operatora przypisania. Z pamięci historia tego była mniej więcej taka:
list.__iadd__()
Metoda została zaimplementowana, aby po prostu wywołać już istniejącąlist.extend()
metodę w Pythonie 2.0. Kiedy iteratory zostały wprowadzone w Pythonie 2.1,list.extend()
metoda została zaktualizowana, aby akceptować dowolne iteratory. Efektem końcowym tych zmian było, żemy_list += my_tuple
działało począwszy od Python 2.1. Jednaklist.__add__()
metoda ta nigdy nie powinna wspierać arbitralnych iteratorów jako argumentu po prawej stronie - uważano to za nieodpowiednie dla silnie typowanego języka.Osobiście uważam, że implementacja rozszerzonych operatorów okazała się w Pythonie zbyt skomplikowana. Ma wiele zaskakujących skutków ubocznych, np. Ten kod:
Druga linia podnosi się
TypeError: 'tuple' object does not support item assignment
, ale operacja i tak jest pomyślnie wykonana -t
nastąpi([42, 44], [43])
po wykonaniu linii, która podnosi błąd.źródło
Większość ludzi spodziewałaby się, że X + = Y będzie równoważne X = X + Y. Rzeczywiście, Python Pocket Reference (wydanie 4) Mark Lutz mówi na stronie 57 „Poniższe dwa formaty są w przybliżeniu równoważne: X = X + Y, X + = Y ”. Jednak osoby, które określiły Python, nie uczyniły ich równoważnymi. Być może był to błąd, który spowoduje godziny debugowania przez sfrustrowanych programistów tak długo, jak długo Python pozostaje w użyciu, ale teraz taki jest właśnie Python. Jeśli X jest mutowalnym typem sekwencji, X + = Y jest równoważne X.extend (Y), a nie X = X + Y.
źródło
Jak wyjaśniono tutaj , jeśli
array
nie implementuje__iadd__
metody,b+=(4,)
byłoby to tylko skrótem,b = b + (4,)
ale oczywiście nie jest, podobniearray
jak__iadd__
metoda implementacji . Najwyraźniej implementacja__iadd__
metody wygląda mniej więcej tak:Wiemy jednak, że powyższy kod nie jest faktyczną implementacją
__iadd__
metody, ale możemy założyć i zaakceptować, że istnieje coś takiego jakextend
metoda, która akceptujetupple
dane wejściowe.źródło