2013-05-02 13 views
72

Próbowałem użyć wielu przydziału, jak pokazano poniżej, aby zainicjować zmienne, ale jestem zdezorientowany przez zachowanie, spodziewam się zmienić przypisanie listy wartości osobno, mam na myśli b [0] i c [0] równe 0 jak poprzednio.Python przypisuje wiele zmiennych do tej samej wartości? lista zachowanie

a=b=c=[0,3,5] 
a[0]=1 
print(a) 
print(b) 
print(c) 

Wynik jest: [1, 3, 5] [1, 3, 5] [1, 3, 5]

Czy to prawda? co powinienem użyć do wielokrotnego przypisania? co różni się od tego?

d=e=f=3 
e=4 
print('f:',f) 
print('e:',e) 

wynik: ('f:', 3) ('e:' 4)

+2

Czy chcesz, aby 'a',' b' i 'c,' do wszystkich wskazywało tę samą wartość (w tym przypadku listę), czy też chcesz 'a = 0',' b = 3', oraz 'c = 5'. W takim przypadku potrzebujesz 'a, b, c = [0,3,5]' lub po prostu 'a, b, c = 0,3,5'. – chepner

Odpowiedz

169

Jeśli idziesz do Pythona z języka C/Java/itp. rodzina, może pomóc przestać myśleć o a jako "zmiennej" i zacząć myśleć o niej jako o "nazwie".

a, i c nie są różnymi zmiennymi o równych wartościach; są to różne nazwy dla identycznej wartości. Zmienne mają typy, tożsamości, adresy i wszelkiego rodzaju podobne rzeczy.

Nazwy nie mają tego. Wartości, oczywiście, i można mieć wiele nazw dla tej samej wartości.

Jeśli podasz Notorious B.I.G. hot dog, * Biggie Smalls i Chris Wallace mają hot doga. Jeśli pierwszy element a zmienić na 1, pierwsze elementy b i c są 1.

Jeśli chcesz wiedzieć, czy dwie nazwy są nazywanie tego samego obiektu, należy użyć operatora is:

>>> a=b=c=[0,3,5] 
>>> a is b 
True 

wtedy zapytać:

co różni się od tego?

d=e=f=3 
e=4 
print('f:',f) 
print('e:',e) 

Tutaj jesteś ponownego wiązania nazwę e wartości 4. To w żaden sposób nie wpływa na nazwy d i f.

W poprzedniej wersji przypisano numer a[0], a nie a. Tak więc, z punktu widzenia a[0], ponownie wiążisz a[0], ale z punktu widzenia a, zmieniasz to w miejscu.

Można użyć funkcji id, co daje pewną unikalną liczbę reprezentującą tożsamość obiektu, aby zobaczyć dokładnie, który to przedmiot, który nawet gdy is nie może pomóc:

>>> a=b=c=[0,3,5] 
>>> id(a) 
4473392520 
>>> id(b) 
4473392520 
>>> id(a[0]) 
4297261120 
>>> id(b[0]) 
4297261120 

>>> a[0] = 1 
>>> id(a) 
4473392520 
>>> id(b) 
4473392520 
>>> id(a[0]) 
4297261216 
>>> id(b[0]) 
4297261216 

Uwaga, a[0] ma zmieniono z 4297261120 na 4297261216 - teraz jest to nazwa dla innej wartości. I b[0] jest teraz również nazwą dla tej samej nowej wartości. To dlatego, że a i b wciąż nazywają ten sam obiekt.


Pod pokrywami, a[0]=1 faktycznie wywołuje metodę na obiekcie listy. (Jest to odpowiednik a.__setitem__(0, 1).) Tak więc, nie jest to w żaden sposób ponowne wiązanie. To tak, jakby dzwonić pod numer my_object.set_something(1). Jasne, prawdopodobnie obiekt ponownie przypisuje atrybut instancji w celu implementacji tej metody, ale to nie jest ważne; ważne jest to, że nic nie przypisujesz, tylko mutujesz obiekt. I tak samo jest z a[0]=1.


user570826 zapytał:

Co jeśli mamy, a = b = c = 10

To jest dokładnie taka sama sytuacja jak a = b = c = [1, 2, 3]: masz trzy nazwy dla tej samej wartości.

Ale w tym przypadku wartość to int, a int s są niezmienne. W obu przypadkach można ponownie powiązać a z inną wartością (np. a = "Now I'm a string!"), ale nie wpłynie to na oryginalną wartość, która nadal będzie oznaczać nazwy dla b i c. Różnica polega na tym, że z listą można zmienić wartość [1, 2, 3] na [1, 2, 3, 4], wykonując np. a.append(4); ponieważ to faktycznie zmienia wartość, b i c są nazwami, b będzie teraz b [1, 2, 3, 4]. Nie ma sposobu, aby zmienić wartość 10 na cokolwiek innego. 10 ma 10 lat, tak jak Claudia, wampir ma 5 lat (przynajmniej dopóki nie zostanie zastąpiona przez Kirsten Dunst).


* Ostrzeżenie: Nie podawaj Notorious B.I.G. Hot dog. Zombie z gatunku Gangsta rap nie powinny być karmione po północy.

+24

Jedno zdanie odnoszące się do raperów, zombie i Gremlinów? Zdobyć. – DSM

+0

Co jeśli mamy "a = b = c = 10;" i kiedy próbujemy zaktualizować wartość b, to działa ona na jakikolwiek inny? chociaż sprawdziłem, czy ich identyfikatory są takie same. – Clayton

+0

@ user570826: '10' jest niezmienne - oznacza to, że nie ma możliwości zaktualizowania wartości, więc twoje pytanie nie ma sensu. Możesz wskazać 'b' na inną wartość, ale nie ma to wpływu na' a' i 'c', które wciąż wskazują na oryginalną wartość. Różnica, która wymienia make, jest taka, że ​​są one zmienne - np. Możesz "dołączyć" do listy lub 'lst [0] = 3', a to zaktualizuje wartość, która będzie widoczna przez wszystkie nazwy dla tej wartości . – abarnert

3

Co trzeba to:

a, b, c = [0,3,5] # Unpack the list, now a, b, and c are ints 
a = 1    # `a` did equal 0, not [0,3,5] 
print(a) 
print(b) 
print(c) 
4

w pierwszym przykładzie a = b = c = [1, 2, 3] ty naprawdę mówią:

'a' is the same as 'b', is the same as 'c' and they are all [1, 2, 3] 

Jeśli chcesz ustawić "a" równe 1, "b" jest równe " 2 'i' c 'równe 3, spróbuj tego:

a, b, c = [1, 2, 3] 

print(a) 
--> 1 
print(b) 
--> 2 
print(c) 
--> 3 

Mam nadzieję, że to pomoże!

12

Tak, to oczekiwane zachowanie. a, b i c są ustawione jako etykiety dla tej samej listy. Jeśli chcesz trzy różne listy, musisz je przypisać indywidualnie. można powtórzyć wyraźnej listę, lub użyć jednego z wielu sposobów, aby skopiować listę:

b = a[:] # this does a shallow copy, which is good enough for this case 
import copy 
c = copy.deepcopy(a) # this does a deep copy, which matters if the list contains mutable objects 

Instrukcje przypisania w Pythonie nie kopiować obiekty - wiążą się one z nazwy do obiektu, a obiekt może mieć tyle etykiet, ile ustawiłeś. Podczas pierwszej edycji, zmieniając [0], aktualizujesz jeden element z pojedynczej listy, do której odwołują się a, b i c. W twoim drugim, zmieniającym e, zmieniasz e na etykietę dla innego obiektu (4 zamiast 3).

8

W pythonie wszystko jest obiektem, także "proste" typy zmiennych (int, float itp.).

Kiedy zmienia się wartość zmiennej, to rzeczywiście zmienia to wskaźnik, a jeśli porównuje się między dwoma zmiennymi To porównuje ich wskaźniki. (Aby było jasne, wskaźnik jest adresem w fizycznej pamięci komputera, gdzie przechowywana jest zmienna).

W wyniku zmiany wartości zmiennej wewnętrznej zmienia się jej wartość w pamięci i wpływa na wszystkie zmienne wskazujące ten adres.

Dla przykładu, kiedy to zrobić:

a = b = 5 

Oznacza to, że A i B wskazuje na ten sam adres w pamięci, która zawiera wartość 5, ale gdy zrobisz:

a = 6 

Nie wpływa na b, ponieważ a wskazuje teraz na inną lokalizację pamięci, która zawiera 6, a b nadal wskazuje na adres pamięci, który zawiera 5.

Ale kiedy to zrobić:

a = b = [1,2,3] 

aib, ponownie wskazuje na tym samym miejscu, ale różnica jest taka, że ​​jeśli zmienisz jedną z wartości listy:

a[0] = 2 

Zmienia wartość pamięci wskazywanej przez a, ale a wciąż wskazuje na ten sam adres co b, w wyniku czego b również się zmienia.

+4

To bardzo mylące. Wskaźniki na pewno nie są widoczne na poziomie Pythona, a co najmniej dwie z czterech głównych implementacji (PyPy i Jython) nie używają ich nawet w implementacji. – abarnert

+1

Zapraszamy do czytania i poznawania wewnętrznych elementów Pythona, a odkryjesz, że każda zmienna w Pythonie jest właściwie wskaźnikiem. –

+4

Nie. W _jednej implementacji Pythona (CPython), każda zmienna jest wskaźnikiem do 'PyObject'. Nie dotyczy to innych implementacji takich jak PyPy czy Jython. (W rzeczywistości nie jest nawet jasne, jak to może być prawdą, ponieważ języki, w które są napisane te implementacje, nie mają nawet wskaźników). – abarnert

8

Można użyć id(name) aby sprawdzić, czy dwa nazwiska reprezentują ten sam obiekt:

>>> a = b = c = [0, 3, 5] 
>>> print(id(a), id(b), id(c)) 
46268488 46268488 46268488 

listy są zmienne; oznacza to, że możesz zmienić wartość bez tworzenia nowego obiektu. Jednak to zależy od tego, w jaki sposób zmienić wartość:

>>> a[0] = 1 
>>> print(id(a), id(b), id(c)) 
46268488 46268488 46268488 
>>> print(a, b, c) 
[1, 3, 5] [1, 3, 5] [1, 3, 5] 

Jeśli przypisać nową listę a, to jego id zmieni, więc nie wpłynie b i wartości c dydaktycznego:

>>> a = [1, 8, 5] 
>>> print(id(a), id(b), id(c)) 
139423880 46268488 46268488 
>>> print(a, b, c) 
[1, 8, 5] [1, 3, 5] [1, 3, 5] 

Liczby są niezmienne, więc nie można zmienić wartość bez tworzenia nowego obiektu:

>>> x = y = z = 1 
>>> print(id(x), id(y), id(z)) 
507081216 507081216 507081216 
>>> x = 2 
>>> print(id(x), id(y), id(z)) 
507081248 507081216 507081216 
>>> print(x, y, z) 
2 1 1 
+1

'id' niekoniecznie jest miejscem w pamięci. Jak mówi [the docs] (http://docs.python.org/2/library/functions.html#id), to zwraca "tożsamość ... liczbę całkowitą ... która jest gwarantowana jako unikalna i stała dla tego obiektu podczas jego dożywotni." CPython używa adresu pamięci jako "id", ale inne implementacje Pythona mogą nie. PyPy na przykład nie. A powiedzenie "dwa vary wskazują na to samo miejsce pamięci" jest mylące dla każdego, kto rozumie to w stylu C. "Dwie nazwy tego samego obiektu" są zarówno dokładniejsze, jak i mniej mylące. – abarnert

+0

@abarnert dzięki za wyjaśnienie, zaktualizowałem odpowiedź. – jurgenreza

2

Dziękuję wszystkim za wyjaśnienia.

kod, który robi to, co trzeba może być to:

#test 
aux=[[0 for n in range(3)] for i in range(4)] 
print('aux:',aux) 
#initialization 
a,b,c,d=[[0 for n in range(3)] for i in range(4)] 
#changing values 
a[0]=1 
d[2]=5 
print('a:',a) 
print('b:',b) 
print('c:',c) 
print('d:',d) 

wynik: ('AUX:' [[0, 0, 0], [0, 0, 0], [0 , 0, 0], [0, 0, 0]]) ('a:', [1, 0, 0]) ('b:', [0, 0, 0]) ('c: ”[0, 0, 0]) ('d:' [0, 0, 5])

Chodzi

18

kaszle

>>> a,b,c = (1,2,3) 
>>> a 
1 
>>> b 
2 
>>> c 
3 
>>> a,b,c = ({'test':'a'},{'test':'b'},{'test':'c'}) 
>>> a 
{'test': 'a'} 
>>> b 
{'test': 'b'} 
>>> c 
{'test': 'c'} 
>>> 
3

Po prostu, w pierwszym przypadku przypisujesz wiele nazw do list. W pamięci tworzona jest tylko jedna kopia listy, a wszystkie nazwy odnoszą się do tej lokalizacji. Zatem zmiana listy przy użyciu którejkolwiek z nazw faktycznie zmieni listę w pamięci.

W drugim przypadku w pamięci tworzone są wielokrotne kopie tej samej wartości. Każda kopia jest więc niezależna od siebie.

Powiązane problemy