Wykład 7 – o zmiennych, czyli jak sobie nie zaszkodzic

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)

#
#

Leave a Reply

Your email address will not be published. Required fields are marked *