# -*- coding: utf-8 -*- #WDI Wykład 6 #O zmiennych, #czyli 100 sposobów strzelenia sobie w stopę #Bartek Wilczyński #zmienne lokalne w funkcjach #Funkcje mogą używać zmiennych lokalnych y=3 def f(): #tu juz nie widze zmiennej globalnej y y=5 return y #mogą też używać zmiennych globalnych def g(): #tu widze zmienna y return y #ale nie mozemy mieszac tych dwoch stylow! #to bedzie dzialac def py(): print y #a to juz nie! def ppy(): print y y=1 #Dlaczego? Dlatego, że zmienna y byłaby globalna w 1 linii i lokalna w 2giej #Czasem chciałbym _zapisać_ coś na zmiennej globalnej #mogę wtedy użyć deklaracji "global" #np. tak: count=0 def add_count(): global count count+=1 return count #to oczywiscie bez global nie zadziala... def add_count(): #global count count+=1 return count #A jakie sa argumenty funkcji: globalne, czy lokalne? y=1 def f(x): x+=1 return x print f(y) y #jak widac - lokalne, #tzn nie nie mozemy nadpisac zmiennej globalnej, przekazanej przez parametr #Ale, czy tak jest zawsze? def f(x): x+=x #jesli uzyje f(liczba), to dobrze y=1 f(y) y #ale dla list dzieje sie cos dziwnego... l=[1,2] f(l) l #co ciekawe, lekka zmiana funkcji f: def f(x): x=x+x #naprawia dzialanie dla list l=[1,2] f(l) l # i nie psuje dla liczb: y=1 f(y) y # O co tu chodzi???? #Podobny mechanizm bedzie dzialal dla list i slownikow przy wstawianiu def f(x): x[0]=1 # l=[1] f(l) l d={} f(d) d #Otóż chodzi o to, że python "ulokalnia" zmienne tylko wtedy #gdy używamy instrukcji przypisania np x=x+x # a nie wtedy gdy "uzywamy" zmiennej: #np x[0]=1 czy nawet x+=x #Ale dlaczego f(x) dzialalo dla liczb? def f(x): def f(x): x+=x print x #jesli uzyje f(liczba), to dobrze y=1 f(y) y #??? I jeszcze dla napisów też: s="ala" f(s) s #??????? #Otóż to się wiąże z różnymi rodzajami zmiennych: # modyfikowalne (mutable) - takie jak listy i słowniki # niemodyfikowalne (immutable) - takie jak liczby i napisy #zmienne modyfikowalne będą "pozwalały" zmieniać swoją wartość #a niemodyfikowalne - nie #to się wiąże z pojęciem referencji, czyli "odnosnika" do wartosci #w pythonie (jak w wiekszosci jezykow dynamicznych) miedzy wartosciami (miejsca w pamięci) #a zmiennymi sa referencje #zwykle podczas przypisania zmieniamy tylko referencje: l=[1,2,3] l2=l l2+=[1] l # zmienna l2 jest tylko "referencja" do zmiennej l # to samo dzieje sie w przypadku przekazywania parametrow #python uzywa przekazywania "przez referencje" #ale zmienne niemodyfikowalne sa bardziej skomplikowane: s="ala" s2=s s2+="ala" #tutaj w momencie przypisania dokonywane jest "odwiazanie" (dereferencja)... print s print s2 #Mozemy sprawdzac "rownosc" referencji przy pomocy funkcji id() i konstrukcji "is" l=[1] l2=l #ta sama lista l3=[1] # inna lista...? id(l) id(l2) id(l3) l==l2 #? l==l3 #? l is l2 #? l is l3 #? #To oczywiscie dziala inaczej dla wartosci niemodyfikowalnych s="ala" s2=s # ten sam napis s3="ala" # inny napis? s is s3 #? #Trzeba tez bardzo uważać zinicjowaniem list... ll= [[]] *5 print ll ll[0].append(0) print ll[0] # ok print ll #oops! #ale tez z parametrami domyslnymi def f(l=[]): l.append(1) return l print f() #ok... print f() # ??? #No to jak "rozplesc" dwie listy? l=[1,2,3] l2=l l3=l[:] l2.append(2) l3.append(3) print l2 print l3 print l #? #ze slownikami jest podobnie, do kopiowania sluzy metoda .copy() d={} d2=d d3=d.copy() d[1]=[] print d,d2,d3 d[1].append(1) print d #ale kopiowanie jest "plytkie"... d4=d.copy() print d4 d[1].append(2) print d4 ## Juz wartosci pod kluczami pozostaja "wspolne".... #Mamy na szczescie modul copy import copy #ktory umie robic kopie "glebokie": d5=copy.deepcopy(d) print d,d5 d[1].append(4) print d,d4,d5 #Sprobujmy sobie jeszcze skomplikowac zycie, #I zdefiniujmy funkcje wewnatrz funkcji: y=1 def f(x): y=5 def g(x): y=x+6 return y print y return y+g(x) f(y) #? y #? y=1 def f(x): y=5 def g(x): global y # mala zmiana? y=x+6 return y print y #tego y'ka nie ruszylismy... return y+g(x) f(y) y # A co sie stanie jesli zmienimy wartosc zmiennej po deklaracji funkcji... x=1 def f(): return x f() x=2 f() #Chyba, ze uzyjemy "domkniecia": def pomnoz_przez(x): def f(y): return x*y return f x=5 przez_5=pomnoz_przez(x) przez_5(10) x=20 przez_5(20) # #