2016-09-24 31 views
8

czytałem ten ciekawy post https://asmeurer.github.io/blog/posts/tuples/Przypisanie Tuple w Pythonie, Czy to błąd w Pythonie?

At autora przypisie przedstawić ten przykład

>>> t=1,2,[3,4] 
>>> t 
(1, 2, [3, 4]) 
>>> t[2]+=[5,6] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'tuple' object does not support item assignment 

Chociaż Python został podniesiony wyjątek, ale to nie zmienia krotki

>>> t 
(1, 2, [3, 4, 5, 6]) 

Nie wiesz, co to jest dzieje się tutaj, czy to błąd?

Zachowanie jest samo w 2.7.10 i 3.5.1

+0

Zauważ, że 't [2] = t [2] + [1,2]' podnosi, ale nie modyfikuje krotki –

Odpowiedz

3

Więc zachowanie += jest nieco dziwne. W przypadku obiektów niezmiennych, takich jak liczby całkowite, należy przypisać nowy obiekt o tej samej nazwie:

a = 4 
a += 3 

Dla typów zmiennych, np. list, obiekt jest zmieniany na miejscu, ale zwraca także ten sam obiekt, który ma zostać przypisany do tej samej nazwy. Pierwszy krok działa z twoją krotką, ale nie drugą.

Dlatego po rozszerzeniu listy wyjątek jest zgłaszany.

3

Dzieje się tak, ponieważ operator += (który jest __iadd__, lub w miejscu dodać wewnętrznie) faktycznie zwraca coś po tym, jak zadanie zostało wykonane. W przypadku list oznacza to wywołanie extend (lub coś podobnego), a zatem nowe elementy już zostały wprowadzone, zanim odwołanie do listy zostało zwrócone do przypisania do t[2], które następnie podnoszą wyjątek. Teraz sprawdzasz wartość, jaką widzisz, że została dodana. Poniżej znajduje się minimalny kod wykazać to:

>>> class AddIDemo(object): 
...  def __init__(self, items): 
...   self.items = list(items) 
...  def __iadd__(self, other): 
...   print('extending other %r' % other) 
...   self.items.extend(other.items) 
...   print('returning self to complete +=') 
...   return self 
...  def __repr__(self): 
...   return self.items.__repr__() 
... 
>>> demo = AddIDemo([1, 2]) 
>>> demo += AddIDemo([3, 4]) 
extending other [3, 4] 
returning self to complete += 
>>> demo 
[1, 2, 3, 4] 
>>> t = 1, 2, demo 
>>> t 
(1, 2, [1, 2, 3, 4]) 
>>> 
>>> t[2] += AddIDemo([5, 6]) 
extending other [5, 6] 
returning self to complete += 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'tuple' object does not support item assignment 
>>> t 
(1, 2, [1, 2, 3, 4, 5, 6]) 
>>> 

Zauważ, że dodałem jeszcze kilka sprawozdań z tuszem, aby pokazać, że funkcja jest nazywany i jak operacja się, jak to zrobić w standardowym list manipulacji poprzez += lub __iadd__ .

0

To nie jest błąd, ale stan, w którym pozostaniemy po podniesieniu wyjątku, może być mylący.

Krotka według projektu nie może zostać zmieniona, ale dotyczy tylko krotki, a nie przedmiotów. Jeśli zawiera zmienną pozycję, którą można zmodyfikować. W twoim przypadku lista jest takim artykułem, który można zmodyfikować.

Teraz operator += mapuje mniej więcej, aby wykonać +, a następnie przypisać go do oryginalnej zmiennej. Operacja + jest możliwa, możesz dodać dwie listy. Ze względu na optykę + jest zaimplementowany jak extend() i aktualizacje na miejscu. Ale zadanie nie powiedzie się, ponieważ nie można zaryzykować krotki.

Istnieją zasadniczo dwie lekcje:

  1. operatorzy Python mogą być realizowane według typu i mogą zachowywać się inna niż trywialne oczekiwania.
  2. Jeśli podczas wywoływania funkcji zostanie zgłoszony wyjątek i nie zostanie on prawidłowo obsłużony, może to oznaczać, że coś nie zostało wcześniej oczyszczone.