In [21]:
%%javascript
$.getScript('http://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')

Funkcje

Definicje funkcji w Pythonie rozpoczynamy slowem kluczowym def

In [ ]:
def suma(a,b):
    return a+b
In [ ]:
suma(3,5)
In [ ]:
suma(3,5,4)

argumentom mozemy nadawac wartosci domyslne

In [ ]:
def suma(a,b,c=0):
    return (a+b+c)
In [ ]:
suma(1,2)
In [ ]:
suma(1,2,3)
In [ ]:
suma('Ala','ma','kota')

argumenty opcjonalne umieszczamy po argumentach wymaganych

In [ ]:
def suma(a,b=0,c): # błąd!
    return (a+b+c)    

argumentow nie musimy podawac 'jawnie' - mozemy uzyc w tym celu sekwencji

In [ ]:
args = (2,3,4)
args, type(args)
In [ ]:
suma(*args)

argumenty mozna tez przekazywac po nazwie

In [ ]:
suma(c=1,b=3,a=2)

argumenty nazwane mozna przekazywac w formie slownika

In [ ]:
args = zip(('c','a','b'), (1,3,2))
kwargs = dict(args)
kwargs
In [ ]:
args = zip(('c','a','b','f'), (1,3,2,8))
kwargs = dict(args)
kwargs
In [ ]:
suma(**kwargs)

co bedzie jesli nie zgadza sie ilosc argumentow?

In [ ]:
args = (2,3,4,5)
type(args)
suma(*args)

mozemy tez zadeklarowac zmienna liczbe argumentow

In [ ]:
def suma(*argumenty):
    wynik = 0
    for x in argumenty:
        wynik += x
    return wynik
In [ ]:
suma(3,2)
In [ ]:
suma(3,2,3,4,5,66,5)
In [ ]:
suma()
In [ ]:
def suma(a, *args):
    wynik = a
    for x in args:
        wynik += x
    return wynik
In [ ]:
suma()
In [ ]:
suma(4,4,5,6)
In [ ]:
argumenty = tuple(range(10))
argumenty
In [ ]:
suma(*argumenty)
In [ ]:
suma(*range(10))
In [ ]:
suma(*range(100))

Wyrażenia lambda

Wyrażenia lambda są uproszczonym schematem definiowania funkcji. Nazwa pochodzi od słowa kluczowego lambda. Ogólna struktura jest ich tworzenia jest nastepujaca:

<nazwa_funkcji> = lambda <zmienne wejsciowe>: <wyrazenie wynikowe>
In [ ]:
# pełna deklaracji funkcji f()
def f(x):
    return x**2

f(10)
In [ ]:
# wersja lambda
g = lambda x: x**2

g(10)
In [ ]:
type(f), type(g)
In [ ]:
# wersja lambda
g = lambda x,y: x+y

g(10,20)
In [ ]:
# wersja lambda
g = lambda *args: sum(args)

g(*range(100))
In [ ]:
g(1,2,4,5,6)

z punktu widzenia Pythona funkcje nazwane i anonimowe sa równoważne:

In [ ]:
type(f), type(g)
In [ ]:
f,g

ciekawe efekty mozna osiagnac łącząc funkcje lambda i wyrażenia warunkowe:

In [ ]:
s = lambda x: "" if x == 1 else ("i" if x in {2,3,4} else "ów")
In [ ]:
type(s)
In [ ]:
for count in range(15):
    print("przetworzono {0} plik{1}".format(count, s(count)))

generatory

Generatory to obiekty Pythona, ktore generują ciąg wartosci zgodnie z zadanym algorytmem. Kolejne wartości ciagu sa generowane na żądanie dzieki czemu oszczedzamy pamiec operacyjna (nie musimy przechowywac wszystkich wyrazów ciagu w pamieci). Poznalismy juz jeden z wbudowanych generatorów Pythona - range(), ale Python pozwala na tworzenie własnych generatorów. Algorytmy generatorów definiujemy podobnie jak funkcje, zastepujac slowo kluczowe return slowem yield.

In [ ]:
list(range(10))
In [ ]:
# trywialny generator
def mojGenerator(n):
    for i in range(n):
        yield i**2
        print(i)
In [ ]:
g = mojGenerator(12)
g
In [ ]:
list(g)
In [ ]:
print(*g)

W odroznieniu od funkcji generatory przechowuja stan pomiedzy wywolaniami - kolejne wywolanie zwracaja kolejne wartosci z ciagu:

In [ ]:
g = mojGenerator(20)
g
In [ ]:
for i in g:
    print(i, end = ' ')
    if i > 80: 
        break
In [ ]:
print(*g)

a po wyczerpaniu ciagu generator nie zwroci nic :)

In [ ]:
list(g)

generatory mozna tez definiowac w uproszczony sposob podobnie jak listy składane

In [ ]:
generator = (x**2 for x in range(20))
print(generator)
In [ ]:
for i in generator:
    print(i, end = ' ')
    if i > 80: 
        break
In [ ]:
list(generator)
In [ ]:
list(generator)

ładowanie bibliotek - polecenie import

Po uruchomienie interpretera Pythona mamy do dyspozycji pewien zbiór domyślnych poleceń i funkcji. Kiedy chcemy używać Pythona w wyspecjalizowanej dziedzinie, na przykład do bardziej złożonych obliczeń, pojawia się pytanie skąd wziąć potrzebne algorytmy?

In [ ]:
math.sin(0)

Twórcy Pythona chwalą się, że dostarczają go z 'bateriami w zestawie'. Oznacza to, że mamy do dyspozycji bogatą bibliotekę gotowych algorytmów do różnych zastosowań. Biblioteka ta jest podzielona na dziedzinowe pakiety, które z kolei dzielą sie na moduły. Dostęp do funkcji zawartych w poszczególnych modułach uzyskujemy poleceniem import. Omówimy krótko wybrane moduły.

math

moduł zawiera podstawowe funkcje matematyczne oraz definiuje stałe $\pi$ i $e$

In [ ]:
import math
In [ ]:
from math import *
In [ ]:
cos(0)
In [ ]:
help(math)

po zaimportowaniu modułu dostep do jego zawartosci uzyskujemy podając nazwę funkcji poprzedzona nazwa modułu, którą w Pythonie nazywamy przestrzenią nazw:

In [ ]:
math.pi, math.e
In [ ]:
math.log(math.e)
In [ ]:
math.cos(0)
In [ ]:
math.sin(1/2*math.pi)

random

Moduł do generowania liczb pseudolosowych

In [ ]:
import random
In [ ]:
help(random)

liczba losowa z przedziału $[0, 1)$:

In [ ]:
random.random()

ustawianie ziarna losowego:

In [ ]:
random.seed(123)

liczba losowa całkowita z przedziału $[a, b]$:

In [ ]:
random.randint(0,100)

liczba losowa z rozkładu normalnego o parametrach $(\mu, \sigma)$:

In [ ]:
random.gauss(0,1)

losowa permutacja sekwencji (zmienia porządek sekwencji):

In [ ]:
a = list(range(20))
print(a)
In [ ]:
random.shuffle(a)
print(a)

dla wygody możemy zmienic nazwę przestrzeni nazw do której wczytujemy zawartość modułu:

In [ ]:
import random as rnd
a = [rnd.randrange(0,100) for x in range(10)] a
In [ ]:
rnd.shuffle(a)
a

możemy też zaimportować wybrane elementy modułu do bieżącej przestrzeni nazw:

In [ ]:
from random import randint
In [ ]:
randint(1,100)

Możliwe jest też zaimportowanie wszytkich składowych modułu do bieżącej przestrzeni nazw. Należy jednak pamietać, że może to doprowadzić do kolizji identyfikatorów (jeśli w bieżącej przestrzeni nazw istnieją identyfikatory takie jak w module to zostaną one 'przesłonięte')

In [ ]:
from random import *
In [ ]:
shuffle(a)
a

time

moduł zawiera funkcje do manipulacji datami i czasem

In [ ]:
import time
In [ ]:
help(time)

czas bieżący w formacie 'timestamp' (ilość sekund od 'dnia zero'):

In [ ]:
time.time()

konwersja wartosci 'timestamp' do formatu 'human readable':

In [ ]:
time.ctime(time.time())

kiedy był 'dzień zero'?

In [ ]:
time.ctime(0)

licznik czasu o wysokiej precyzji -- przydatny do mierzenia interwałów czasowych w przebiegu symulacji:

In [ ]:
time.perf_counter()
In [ ]:
time.perf_counter() - time.perf_counter()
In [ ]:
print('%.12f' % (time.perf_counter() - time.perf_counter()))
In [ ]:
print('%.12f' % (time.time() - time.time()))
In [ ]:
print('%.12f' % (time.process_time() - time.process_time()))
In [ ]:
time.process_time() - time.process_time()

czas bieżący (lokalny) w postaci krotki nazwanej (named tuple):

In [ ]:
a = time.localtime()
a
In [ ]:
a.tm_year, a[1]
In [ ]:
a[:]