Commit 17c22743 by Patryk Czarnik

teoria funkcji - trudne sprawy :)

parent 46edaa06
# Zmienna definiowana na poziomie pliku to jest "zmienna globalna"
gloobalna = 'lalala'
# także gdy jest w jakimś if-e, try-u itp.
if 5 > 0:
globalna = 100
def aaa(a):
# jeśli w obrębie funkcji stosujemy przypisanie wartości na zmienną,
# a ta zmienna nie jest zadeklarowana jako global,
# to Python przyjmuje, że jest zmienna lokalna
# Zmienna definiowana wewnątrz funkcji, to "zmienna lokalna"
lokalna = 50
# odczyt zmiennych
# własny parametr - bez problemu
print(a)
# zmienna lokalna - bez problemu
print('aaa lokalna:', lokalna)
# zmienna globalna - można czytać bez deklarowania
# o ile wcześniej zmienna została zdefiniowana przed uruchomieniem tej funkcji
print('aaa globalna:', globalna)
inna1()
print('aaa lokalna po raz drugi:', lokalna)
print('globals:', globals())
print('locals:', locals())
print('koniec aaa')
def inna1() :
print('inna1')
# w jednej funkcji nie ma dostepu do zmiennej lokalnej innej funkcji
# print(lokalna)
def bbb(a):
# modyfikacja zmiennych
# parametr - można
a += 1
print('bbb: parametr a = ', a)
# lokalna - można stworzyć i modyfikować
lokalna = 40
lokalna += 1
print('bbb lokalna', lokalna)
# globalna?
# Jeśli bez deklarowania global na zmienną o takiej samej nazwie jak jakaś zmienna globalna
# wpiszę wartość, to tak naprawdę jest to deklaracja zmiennej lokalnej.
# "przesłonięcie" zmiennej globalnej przez zmienną lokalną
globalna = 500
globalna += 1 # zmiana zmiennej lokalnej o nazwie "globalna"
print('bbb globalna', globalna) # tak naprawdę zmienna lokalna tej funkcji
print('globals:', globals())
print('locals:', locals())
print('koniec bbb')
def ccc():
# Jeśli nie deklarując global próbuję
# najpierw odczytać zmienną globalną
print(globalna)
# A następnie zapisać / zmienić
globalna = 500
globalna += 1
print(globalna)
# To już przy oczycie pojawia się błąd
# local variable 'globalna' referenced before assignment
def ddd():
# Jeśli wewnątrz funkcji świadomie chcemy modyfikować zmienną globalną,
# to musmy ją zadeklarować pisząc global
global globalna
global nowa_globalna
nowa_globalna = 641
# global x, y, z
print('ddd globalna', globalna)
print('ddd zmienia globalną')
globalna = 700
globalna += 1
print('ddd globalna', globalna)
print('koniec ddd')
globalna = 200
print('program globalna', globalna)
aaa(33)
#ERR print('lokalna odczytywana w programie:', lokalna)
print()
print('program globalna', globalna)
bbb(44)
print('program globalna', globalna)
print()
# błąd gdy uruchomimy
# ccc()
ddd()
print('program globalna', globalna)
print('nowa globalna:', nowa_globalna)
print()
# globalne x i y = 100
x = 100
y = 100
def ggg():
# Tutaj widzimy zmienne globalne, a nie zmienne z fff, chociaż fff wywołał ggg
print('ggg x = ', x, ', y = ', y)
def fff(x):
y = 2*x
print('fff x = ', x, ', y = ', y)
x += 1
print('fff x = ', x, ', y = ', y)
ggg()
print('fff x = ', x, ', y = ', y)
print('koniec fff')
fff(44)
print()
globalna_lista = ['oryginał']
def eee():
# modyfikacja obiektu "w środku" to nie jest to samo co zapisanie zmiennej
# formalnie rzecz biorąc, my tutaj zmienną globalną odczytujemy, a de facto możemy zmodyfikować bez piosania global
globalna_lista[0] = 'podróbka'
globalna_lista.append('nowy element')
# zabronione jest to:
# globalna_lista = ['nowa lista']
print('lista1', globalna_lista)
eee()
print('lista2', globalna_lista)
# W Pythonie istnieje wiele sposobów deklarowania i przekazywania parametrów do funkcji.
# 1) Normalne parametry pozycyjne.
def aaa(a, b, c):
print(f'aaa: a={a}, b={b}, c={c}')
# Podczas wywołania trzeba przekazać wszystkie te parametry w takiej kolejności, w jakiej zostały zadeklarowane.
aaa('Ala', 'Basia', 'Celina')
# aaa('Ala', 'Basia')
# aaa('Ala', 'Basia', 'Celina', 'Dorota')
# 2) Podczas wywołania parametry można też przekazywać po nazwie (keyword arguments):
aaa(a='Alicja', b='Barbara', c='Czesław')
# aaa(a='Alicja', bee='Barbara', cee='Czesław')
# Wówczas kolejność parametrów można zmienić
aaa(b='Bolek', c='Czarek', a='Adrian')
# Można kilka pierwszych parametrów podać pozycyjnie, a kilka kolejnych wg nazwy:
aaa('Ala', c='Celina', b='Bożena')
# Zawsze najpierw parametry pozycyjnie (positional), a później z nazwą (keyword), nigdy odwrotnie
# aaa(b='Bożena', 'Ala', 'Celina')
print()
#########
# 3) W deklaracji funkcji można podać domyślne wartości parametrów.
# Można dla wszystkich, albo tylko dla pewnej części. Jeśli podajemy domyslne wartości dla niektórych parametrów,
# to muszą to być parametry na końcu.
# Parametry z domyślną wartością / parametry opcjonalne.
def bbb(a, b, c='Celina', d='Dorota', e='Elżbieta'):
print(f'bbb: a={a}, b={b}, c={c}, d={d}, e={e}')
bbb('Ala', 'Basia', 'Cezary', 'Donald', 'Eliza')
bbb('Ala', 'Basia', 'Cezary')
# źle - trzeba podać wszystkie wymagane parametry
# bbb('Ala')
# za dużo to też źle
# bbb('Ala', 'Basia', 'Celina', 'Dorota', 'Elżbieta', 'Franek')
# Jeśli wywołując podamy parametry wg nazwy, to mamy możliwość
# pominięcia parametru który jest gdzieś w środku, a podania parametru który jest dalej, np. ostatniego.
bbb('Alicja', 'Barbara', e='Eleonora')
# None to nie to samo. Zostanie normalnie wczytany przez funkcję
bbb('Alicja', 'Barbara', c=None, d=None, e='Eleonorka')
bbb(e='Eleonora', a='Agata', b='Balbina', d='Dziadek')
# Muszę jednak podać wszystkie te, które nie mają wartości domyślnych
#ERR bbb(e='Eleonora', b='Balbina', d='Dziadek')
# def bbbb(a, b='Barbara', c, d='Dorota', e='Elżbieta'):
# print(f'bbb: a={a}, b={b}, c={c}, d={d}, e={e}')
print()
# 4) Jeśli w deklaracji funkcji użyjemy parametru z pojedynczą gwiazdką,
# to przechwyci on wszystkie parametry pozycyjne podane w momencie wywołania,
# które nie dopasowały się do normalnych parametrów.
def ccc(*args):
print(f'ccc: args={args}')
print(f' typem parametru jest {type(args)}, a długość = {len(args)}')
if args:
print('Element zerowy:', args[0])
print('----')
ccc()
ccc('Jeden')
ccc('Ala', 'Basia', 'Celina')
ccc('Ala', 'Basia', 'Celina', 'Dorota', 'Eliza', 'Fela', 'Grażyna')
ccc('napis', 3.14, [3,2,1], None, 44)
print()
def proba_modyfikacji(*args):
# args[0] = 'cośnowego'
przekazana_lista = args[1]
przekazana_lista.append(33)
print('hahaha')
lista = [10,20]
print('lista', lista)
proba_modyfikacji('cokolwiek', lista, 'cośinnego')
print('lista', lista)
print()
# Parametr nie musi nazywać się args - ale taka jest konwencja.
# Przykład zastosownia (type hint przy parametrze z gwiazką dotyczy typu elementu/pojedynczego parametru)
def suma(*liczby:int):
s = 0
for x in liczby:
s += x
return s
print( suma(1,2,3) )
print( suma(1,3,5,7,9) )
print( suma() )
print()
# Parametr z gwiazdką może być podany tylko jeden i tylko po wszystkich parametrach pozycyjnych
def ddd(a, b, c='Celina', *args):
print(f'ddd: a={a}, b={b}, c={c}, args={args}')
ddd('Ala', 'Basia', 'Cezary', 'Darek', 'Edek')
def eee(a, b, *args, c='Celina'):
print(f'eee: a={a}, b={b}, c={c}, args={args}')
eee('Ala', 'Basia', 'Cezary', 'Darek', 'Edek')
# Jeśli funkcja ma zadkelarowane jakieś parametry za parametrem *args,
# to da się je przekazać wyłącznie po nazwie.
eee('Ala', 'Basia', c='Cezary')
# tutaj Ala i Basia są przekaza jako "positional arguments"
# natomiast Cezary jako "keyword argument"
# Tak właśnie działa print
def my_print(*args, end='\n', sep=' ', file=None):
print('--- myprint: ---')
print(*args, sep=sep, end=end, file=file)
print('----------------')
my_print('Ala', 'ma', 'kota')
my_print('Ola', 'ma', 'psa', end='!', sep=',')
# Właśnie tak działa print: parametry end oraz sep można przekazać tylko po nazwie
# print('ala', 'ola', end=';', sep=',', file=plik_wynikowy)
def fff(a, b, *args, c, d='Dorota'):
print(f'fff: a={a}, b={b}, c={c}, args={args}')
fff('Adrian', 'Bolek', 'Cezary', 'Duduś', c='Czesław', d='Dariusz')
#ERR fff('Adrian', 'Bolek', 'Cezary', 'Duduś', 'Czesio', 'Darek')
print()
# Przy takim zapisie parametry za gwazdką (tutaj c i d)
# można przekazywać tylko poprzez nazwę
def kkk(a, b, *, c, d):
print(f'kkk: a={a}, b={b}, c={c}, d={d}')
# kkk('Ala', 'Basia', 'Celina', 'Dorota')
kkk('Ala', 'Basia', c='Celina', d='Dorota')
kkk(a='Ala', b='Basia', c='Celina', d='Dorota')
kkk(b='Basia', c='Celina', a='Ala', d='Dorota')
# 5)
# Parametr z dwiema gwiazdkami - tradycyjna nazwa **kwargs
# - przechwytuje wszystkie parametry w wywołaniu podawane z nazwami,
# które nie były jawnie zadeklarowane wcześniej.
def ggg(**kwargs):
print(f'kwargs: {kwargs}')
print(f' typem kwargs jest {type(kwargs)}')
# Ta funkcja nie przyjmie parametrów pozycyjnych
# ggg('Ala', 'Ola')
ggg(a='Ala', k='Kasia', x=113)
ggg()
print()
# Można wszystkie techniki połączyć. Konwencja Pythona: argumenty specjalne nazywają się *args i **kwargs
def hhh(a, b='Baba', *args, **kwargs):
print('a:', a)
print('b:', b)
print('args :', args)
print('kwargs:', kwargs)
print()
hhh('Ala', 'Basia', 'Celina', 'Dorota', 'Ela', 'Felicja')
hhh(a='Ala', b='Basia', c='Celina', d='Dorota', e='Ela', f='Felicja')
hhh('Ala', 'Basia', 'Celina', 'Dorota', e='Ela', f='Felicja')
hhh('Ala')
hhh('Ala', d='Dorota', e='Ela', f='Felicja')
print()
# 6) notacji "gwiazdkowej" można też użwać podczas wywoływania funkcji
def iii(*args):
print(f'iii {args}')
iii('Ala', 'Basia', 'Celina')
lista = ['Alicja', 'Barbara', 'Celina', 'Dagmara']
#iii(lista) # lista byłaby pierwszym elementem tupli args
iii(*lista) # elementy wzięte z listy zostały wstawione do args
# Nawet jeśli funkcja przyjmuje "normalne paramenty",
# to w momencie wywołania można przekazać listę wartości (pisząc *lista)
# a Python sobie wyciągnie elementy z tej listy.
def jjj(a, b, c, d='Dorota', e='Eliza'):
print(f'jjj: a={a}, b={b}, c={c}, d={d}, e={e}')
lista = ['Alicja', 'Barbara', 'Celina', 'Dagmara']
jjj(*lista)
# w tym przypadku to jest równoważne
jjj(lista[0], lista[1], lista[2], lista[3])
jjj('Alicja', 'Barbara', 'Celina', 'Dagmara')
# też OK jjj('Ala', *lista)
# To samo ze słownikiem:
slownik = {'a': 'Adam', 'b':'Bolesław', 'c':'Cezary', 'e':'Edward'}
jjj(*lista, **slownik)
# w tym przypadku to jest równoważne
jjj(a=slownik['a'], b=slownik['b'], c=slownik['c'], e=slownik['e'])
# Gdyby słownik zawierał nieoczekiwane argumenty, to spowoduje to błąd.
# (chyba że funkcja ma wpisane **kwargs)
# slownik = {'a': 'Adam', 'b':'Bolesław', 'c':'Cezary', 'e':'Edward', 'z':'Zenon'}
# jjj(**slownik)
# Od Pythona 3.5 częścią składni stały się "type hints", czyli informacje o typach zmiennych i funkcji,
# do tej pory stosowane w docstringach i komentarzach.
# Informacje o typie mają charakter niezobowiązujących podpowiedzi.
# Stanowią dokumentację oraz wpływają na podpowiedzi dawane przez edytory oraz narzędzia kontroli jakości kodu.
# Ale nie są weryfikowane przez interpreter Pythona!
# typ zmiennej:
x:int = 15
imie:str = "Ala"
print(x)
# nadal można na zmienną wpisać wartość innego typu i to nie będzie błąd Pythona (tylko edytor na nas nakrzyczy)
x = 'Ala ma kota'
print(x)
# Typ parametrów i wyniku funkcji:
def pole_kola(r:float) -> float:
import math
return math.pi * r**2
# Do opisania typów kolekcji oraz pewnych szczególnych sytuacji, używa się definicji z moduły typing
import typing
def wypisz_n_razy(napis:str, ile_razy:int=1) -> typing.NoReturn:
for i in range(ile_razy):
print(napis)
def pierwsza_polowa(dane:typing.Sequence) -> typing.List:
return list(dane[0:len(dane)//2])
def wypisz_cennik(cennik:typing.Dict[str, int]) -> typing.NoReturn:
for k, v in cennik.items():
print(f'{k} kosztuje {v}')
def posortuj_teksty(teksty:typing.List[str]) -> typing.List[str]:
import locale
locale.setlocale(locale.LC_COLLATE, '')
return sorted(teksty, key=locale.strxfrm)
def fikumiku(arg:int) -> typing.Union[str,int]:
if arg % 2 == 0:
return f"napis {arg}"
else:
return 10*arg # liczba
# Pewien problem stanowi odwołanie się do klasy wewnątrz jej definicji.
# Przyjęto, że w tej sytuacji wpisuje się nazwę tej klasy jako string.
class Punkt:
def __init__(self, x:float=0, y:float=0):
self.x = x
self.y = y
def przesuniety(self, dx:float, dy:float) -> 'Punkt':
'''Zwraca punkt przesunięty o podane współrzędne jako nowy obiekt'''
return Punkt(self.x + dx, self.y + dy)
# Ponieważ w Pythonie funkcje są traktowane na równi ze zmiennymi globalnymi,
# można omyłkowo nadpisać funkcję wbudowaną lub własną:
a = 5
b = 7
c = 4
max = max(a, b, c)
print('Maksymalna wartość to:', max)
x = 3.14
y = 77.7
z = 2**0.5 # pierwiastek z dwóch
max = max(x, y, z)
# błąd, bo teraz pod nazwą max nie mam już wbudowanej funkcji Pythona, tylko wartość 7
print('Maksymalna wartość to:', max)
miasta = ['Warszawa', 'Kraków', 'Łódź', 'Wrocław', 'Poznań']
print(*miasta, sep=';')
#print(miasta, sep=';')
from random import randint
zakres = (1, 10)
# zamiast pisać tak lub tak:
# x = randint(1, 10)
# x = randint(zakres[0], zakres[1])
# można w stylu "pajtonicznym":
x = randint(*zakres)
y = randint(*zakres)
print('Wylosowane liczby:', x, y)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment