Pridruživanje lista

I u C-u i u pythonu postoje sličnosti pri radu sa stringovima i sa listama (poljima). Najveća razlika između stringova i lista u pythonu dolazi od toga da su stringovi u pythonu nepromjenjivi (immutable):

a = "100"
#a[2] = "1" ovo bi izbacilo grešku

Napomena

U pythonu postoji i immutable verzija liste i taj tip podataka se naziva tuple. Za razliku od liste koja se zadaje uglatim, tuple se zadaje okruglim zagradama npr. a = (1, 2, 3). O razlici lista i tupleova na: http://stackoverflow.com/a/1708538

Pridruživanje vs. shallow copy

Pridruživanjem lista pomoću operatora pridruživanja (=) ne kopira se sadržaj liste. Samo se varijabli slijeva pridruži postojeća lista navedena desno od operatora pridruživanja. U sljedećem primjeru vidimo da nakon pridruživanja a i b pokazuju na isti objekt što znači da ako se naknadno promijeni a[0], promijeni se i b[0].
>>> a=[1,2,3]
>>> b=a
>>> a[0]=11
>>> a
[11, 2, 3]
>>> b
[11, 2, 3]
U sljedećem primjeru pomoću a[:] cijeli sadržaj liste je kopiran i ta nova kopija je pridružena varijabli b. Sad možemo mijenjati a neovisno o b.
>>> a=[1,2,3]
>>> b=a[:]
>>> a[0]=11
>>> a
[11, 2, 3]
>>> b
[1, 2, 3]

Shallow copy vs. deep copy

U sljedećem primjeru kopiramo listu koja u sebi sadrži referencu na drugu listu. Za kopiranje koristimo shallow-copy način iz prethodnog primjera. U prethodnom primjeru, shallow-copy je omogućio da liste a i b budu neovisne. Ovdje vidimo da to još uvijek vrijedi za prvi nivo liste. Sad je jasno zašto se ovo zove plitko kopiranje (shallow copy): kopiran je samo prvi nivo liste, drugi nivo je kopiran kao pokazivač, pa u listi b još uvijek “živi” isti objekt c koji živi u a.
>>> c=[4,5,6]
>>> a=[1,2,c]
>>> b=a[:]
>>> a[0]=11
>>> c[0]=44
>>> a
[11, 2, [44, 5, 6]]
>>> b
[1, 2, [44, 5, 6]]
Funkcija copy.deepcopy() služi da se kopiraju svi nivoi liste, tako da su u ovom primjeru a i b potpuno neovisni.
>>> import copy
>>> c=[4,5,6]
>>> a=[1,2,c]
>>> b=copy.deepcopy(a)
>>> a[0]=11
>>> c[0]=44
>>> a
[11, 2, [44, 5, 6]]
>>> b
[1, 2, [4, 5, 6]]

Razne operacije koje sve funkcioniraju kao shallow copy

>>> import copy
>>> c=[4,5,6]
>>> a=[1,2,c]
>>> b=copy.copy(a)
>>> a[0]=11
>>> c[0]=44
>>> a
[11, 2, [44, 5, 6]]
>>> b
[1, 2, [44, 5, 6]]
>>> c=[4,5,6]
>>> a=[1,2,c]
>>> b=list(a)
>>> a[0]=11
>>> c[0]=44
>>> a
[11, 2, [44, 5, 6]]
>>> b
[1, 2, [44, 5, 6]]
>>> c=[4,5,6]
>>> a=[1,2,c]
>>> b=a[:]
>>> a[0]=11
>>> c[0]=44
>>> a
[11, 2, [44, 5, 6]]
>>> b
[1, 2, [44, 5, 6]]
>>> c=[4,5,6]
>>> a=[1,2,c]
>>> b=a+[]
>>> a[0]=11
>>> c[0]=44
>>> a
[11, 2, [44, 5, 6]]
>>> b
[1, 2, [44, 5, 6]]

Usporedba immutable i mutable veličina

Sve varijable u pythonu su interno pointeri. Python u pravilu ne omogućuje očitavanje adresa iako je u nekim implementacijama pythona (npr. u uobičajenoj implementaciji CPython) adresu moguće očitati pomoću id(a).

Immutable Mutable
a = "123" # a pokazuje na "123"
b = a     # b pokazuje na isti taj "123"
a = a + "4" # a pokazuje na novi string "1234"
   # b pokazuje još uvijek na onaj stari "123"
print(a)
print(b)
1234
123

Treba primijetiti da se b nije promijenio jer se stringovi ne mogu mijenjati, samo može nastati novi string.

a = [1,2,3] # a pokazuje na objekt [1,2,3]
b = a       # b pokazuje na isti taj objekt [1,2,3]
a.append(4) # objekt se promijenio na [1,2,3,4]
print(a)    # svi koji pokazuju na taj 
print(b)    #   objekt vide promjenu
[1, 2, 3, 4]
[1, 2, 3, 4]

Treba primijetiti da se i b promijenio zato što je pokazivao na listu koja se u međuvremenu promijenila.

Mutable (inplace operacija) Mutable (operacija koja kopira)
a = [1,2,3]
b = a     
a += [4] 
print(a) 
print(b)
[1, 2, 3, 4]
[1, 2, 3, 4]

Isto kao primjer s list.append() (ostale moguće operacije u tablici o operacijama nad mutable tipovima Mutable Sequence Types).

a = [1,2,3]
b = a     
a = a + [4] 
print(a) 
print(b)
[1, 2, 3, 4]
[1, 2, 3]

Iako je tip mutable, kad se umjesto += koristi +, rezultat je stvaranje novog neovisnog objekta, a ne proširivanje postojećeg.

Literatura