Dzis zamiat slajdow do wykladu plik z kodem i komentarzami:
#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)
#
#