• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Różnice w działaniu funkcji

Object Storage Arubacloud
0 głosów
222 wizyt
pytanie zadane 21 września 2015 w Python przez Macek Kolo Mądrala (5,480 p.)

Mam dwie funkcje:

def func(a=""):
     a += "1"
     print(a)
 
func()
func()
func()
 
def func1(a=[]):
     a += [1]
     print(a)
 
func1()
func1()
func1()

Co zwrócą, to nie filozofia dla mnie odgandąć. Jednak zastanawiam się dlaczego przy drugiej funkcji będzie [1], [1,1] i [1,1,1], a przy pierwszej wynik cały czas jest '1'? Od czego to zależy? I jak będzie sytuacja wyglądała przy krotkach i zbiorach? 

3 odpowiedzi

–1 głos
odpowiedź 21 września 2015 przez Szykem2 Nałogowiec (29,510 p.)
wybrane 21 września 2015 przez Macek Kolo
 
Najlepsza

String nie jest skomplikowaną strukturą danych i jest przesyłany przez wartość, a że ty nie przesyłasz stringa to za każdym razem tworzysz nowy pusty string jak zrobisz:

def func(a):
    a += str(1)
    print(a)
    return a
  
b = ""
b = func(b)
b = func(b)
b = func(b)
print b

to działa tak samo innej opcji nie widzę. Cały program do sprawdzenia działania:

def func(a):
    a += str(1)
    print(a)
    return a
  
b = ""
b = func(b)
b = func(b)
b = func(b)
print(b)

def func1(a = []):
     a += [1]
     print(a)

c = []
func1(c)
func1(c)
func1(c)
print(c)

def func3(a = {}):
     a["one"] = 1
     print(a)
	 
d = {}
func3(d)
func3(d)
func3(d)
print(d)

def func4(a):
	b = list(a)
	b += [1]
	a = tuple(b)
	print(a)
	return a

e = ()
e = func4(e)
e = func4(e)
e = func4(e)
print (e)

W ostatnim przypadku mamy też przez wartość bo tuple(tak wolę angielską nazwę) nie powinien być modywikowany a ze słownikiem to wiadomo. Jak już jeden klucz istnieje to drugi raz się go nie zrobi.

komentarz 21 września 2015 przez adrian17 Ekspert (344,860 p.)
edycja 21 września 2015 przez adrian17

To nie jest prawda. W Pythonie nie ma czegoś takiego jak "przekazywanie przez wartość" ("przez referencję" w rozumieniu na przykład C++'owym też nie; jakby się bardzo czepiać to najbliższe prawdzie jest "przekazuję referencję przez wartość").

to za każdym razem tworzysz nowy pusty string

To też nie jest prawda, za każdym razem to jest ten sam obiekt i to się tyczy wszystkich Twoich przykładów.

Prawdziwa różnica polega na tym, że w przypadku stringów "a += b" oraz "a = a + b" zachowują się tak samo: tworzą nowy string i przypisują go do a (bo stringi w Pythonie są niemutowalne). Ale dla list "a += b" dla odmiany modyfikuje istniejący obiekt (a) Dowód:

>>> a=[]
>>> b=a
>>> a is b # a i b wskazuja na ta sama liste
True
>>> b += [1]
>>> b
[1]
>>> a
[1]
>>> a is b # to wciaz ten sam obiekt
True
>>> b = b + a
>>> b
[1, 1]
>>> a
[1]
>>> a is b # to juz inny obiekt
False
+1 głos
odpowiedź 21 września 2015 przez Tomatosoup Pasjonat (18,530 p.)

Dzieje się tak dlatego, że listy są zmiennym typem danych ( mutable ), więc do funkcji zostaje wysłany odnośnik do danej listy ( reference ), wtedy każda operacja modyfikuje oryginał.

Stringi natomiast, są typem danych niezmiennym ( czyli immutable - btw. nie polecam się uczyć pythona po polsku ), więc do funkcji zostaje wysłana kopia danego stringa. Jaki więc można zmienić stringa poprzez funkcję, na przykład dodać do niego "abc" lub cokolwiek innego ?: 

def func(old_string):
	something = "abc"
	new_string = old_string + something
	return new_string

Jest to na pewien sposób obejście - musimy potem posługiwać się zwracaną wartością przez funkcje a nie bezpośrednio stringiem który wysłaliśmy do funkcji.

komentarz 21 września 2015 przez adrian17 Ekspert (344,860 p.)
Patrz moja odpowiedź do drugiej odpowiedzi - masz rację o mutowalności/niemutowalności listy i stringa, ale nie o kopiowaniu argumentów. Ba, z definicji jedną z głównych zalet niezmienności stringów jest to że nigdy nie trzeba ich kopiować.
komentarz 21 września 2015 przez Tomatosoup Pasjonat (18,530 p.)
Faktycznie - musiałem kiedyś źle zrozumieć to co pisali na so i już tak zapamiętałem:

http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference
0 głosów
odpowiedź 13 października 2015 przez furas Maniak (53,800 p.)

Dziwne zachowanie kodu 

def func1(a=[]):

wynika stąd, że Python wartości domyślne (w powyższym jest to [ ] )
tworzy tylko raz - przy uruchamianiu programu - a potem korzysta z odnośnika do tej wartości. 

Przy każdym uruchomieniu tej funkcji bez podania własnego parametru "a"
korzysta ona z tej wczejśniej utworzonej listy a nie tworzy za każdym razem nowej.

Można powiedzieć, że jest to równoważne z 

ukryta_lista = [] # utworzenie jednej listy na poczatku
def func1(a=ukryta_lista): # przypisywanie `ukrytej_listy` do `a`

Do tego dochodzi fakt, że po poniższym przypisaniu 

a = ukryta_lista

Zmienna `a` nie zawiera kopii `ukrytej listy` tylko wskazuje dokładnie na `ukrytą listę` (na to samo miejsce w pamięci). Tak więc późniejsze działania na liście `a` jest równoważne działaniu bezpośrednio na `ukrytej liście`.

Problem rozwiązuje się z użyciem `None`

def func1(a=None):
    if a is None:
        a = []

 

Podobne pytania

0 głosów
1 odpowiedź 69 wizyt
pytanie zadane 14 lutego w Python przez tubylec01 Obywatel (1,290 p.)
0 głosów
1 odpowiedź 650 wizyt
pytanie zadane 25 lipca 2017 w Python przez czujek22 Dyskutant (7,670 p.)
0 głosów
0 odpowiedzi 218 wizyt
pytanie zadane 3 czerwca 2023 w Python przez whiteman808 Obywatel (1,820 p.)

92,583 zapytań

141,434 odpowiedzi

319,669 komentarzy

61,966 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...