Prezentacja z wykładu Plik

Transkrypt

Prezentacja z wykładu Plik
Informatyka 2015/16
wykład 6
Funkcje cz. 2
Dr inż. Witold Nocoń (p. 230)
Nasze zaawansowanie w nauce programowania
Nauka zasad języka, jego składni i
mechanizmów
Algorytmy
(tu nie ma końca….)
Narzędzia (np. obsługa plików. Turtle, pygame, tkinter,
komunikacja (TCP), bazy danych, grafika komputerowa…
postępy
Zakresy
Zakres wbudowany (Python)
Nazwy przypisane w module wbudowanym
Zakres globalny
Nazwy przypisane na najwyższym poziomie pliku modułu lub
zadeklarowane jako globalne (*) w instrukcji def wewnątrz tego
pliku
Zakres funkcji zawierających
Nazwy z zakresu lokalnego wszystkich funkcji
zawierających, od wewnętrznej do zewnętrznej
Zakres lokalny (funkcja)
Nazwy przypisane w dowolny
sposób wewnątrz funkcji
(niezadeklarowane jako global)
(*) będzie omówione później
Zakresy – zasady użycia zmiennych
• Jeżeli w wyrażeniu pojawia się zmienna (nazwa)
– Python szuka jej w zakresie lokalnym. Jeśli znajduje
bierze jej wartość i wstawia w miejsce nazwy
– Jeśli nie ma w zakresie lokalnym, to szuka w zakresie
„zawierającym” (w przypadku funkcji zagnieżdżonych)
– Jeżeli jeszcze nie ma to szuka w zakresie globalnym
– Jeżeli jeszcze nie znalazł, to szuka w zakresie
wbudowanym
– Jeżeli mimo tego nie znalazł zwraca błąd!
Zmienne globalne – deklaracja
global
• Istnieje możliwość modyfikacji zmiennych globalnych
X = 100
def funkcja():
global X
X = 9
print(X)
funkcja()
print(X)
Zmienne globalne – deklaracja
global
• Używanie (modyfikacja) zmiennych globalnych
jest bardzo złą praktyką programistyczną
• Należy ją stosować tylko w wyjątkowych lub
pomocniczych przypadkach
• Funkcja jest najlepiej napisana jeśli wszystkie
wartości jakie ma dostać otrzymuje poprzez
argumenty zaś wartości które ma obliczać zwraca
przez wartość funkcji
• Jeżeli program tego oczekuje funkcje mogą
modyfikować argumenty przekazane
Dobre praktyki dotyczące pisania
funkcji
• Najlepiej jeśli funkcje:
– Nie korzystają ze zmiennych globalnych
– Wszystkie wartości jakie otrzymują dostają
jako argumenty!
– Nie modyfikują zmiennych typów
przekazanych jako argumenty jeśli
pozostały kod tego nie oczekuje
Przykład
• Obliczenie mediany z ciągu wartości.
(https://pl.wikipedia.org/wiki/Mediana)
• Patrz przykłady dołączone do materiałów
– mediana_01.py – „niechcący” modyfikuje
przekazaną listę
– mediana_02.y – tworzy sobie kopię dzięki czemu
nie modyfikuje listy oryginalnej
Przykład
• Znajdowanie najmniejszego wspólnego
mianownika dla dwóch ułamków
(najmniejszy wspólny mianownik.py).
• Tworzymy dwie funkcje:
– najmniejszyMianownik(mian1,mian2)
– funkcja zwracając najmniejszy wspólny
mianownik
– czescWspolna(s1,s2) – funkcja zwracająca
część wspólną z dwóch list (bez powtórzeń)
Argumenty domyślne
• W definicji funkcji można określić
domyślne wartości argumentów
def jakasFunkcja(a,b=7,c=1):
return 100*a + 10*b + 1*c
x = jakasFunkcja(1,2,3)
print(x)
x = jakasFunkcja(1,2)
print(x)
x = jakasFunkcja(1)
print(x)
Przekazanie argumentów przez nazwę
def jakasFunkcja(a,b=7,c=1):
return 100*a + 10*b + 1*c
x = jakasFunkcja(100,c=2)
print(x)
x = jakasFunkcja(c=5,b=3,a=1)
print(x)
Funkcje rekurencyjne
• Silnia (silnia.py)
– Z definicji:
Ten sam problem co
problem wyjściowy ale
prostszy!
n! = n* (n-1)!
Mnożenie jest problemem
banalnym
Silnia
def silnia(n):
if n==0:
return 1
else:
return n*silnia(n-1)
silnia(3):
…
return 3*silnia(2)
Silnia
silnia(2):
…
return 2*silnia(1)
silnia(1):
…
return 1*silnia(0)
silnia(0):
…
return 1
Funkcje rekurencyjne
• Wieża z Hanoi (hanoi.py)– przenieść 64 dyski z „1” na „2”
• Tylko jeden dysk na raz
• Nie wolno kłaść większego na mniejszym
1
2
3
Funkcje rekurencyjne
• Rozwiązanie rekurencyjne:
1. Przenieść n-1 na tymczasowy słupek „3”
1
2
3
Funkcje rekurencyjne
• Rozwiązanie rekurencyjne:
2. Przenieś 1 na tymczasowy słupek „3”
1
2
3
Funkcje rekurencyjne
• Rozwiązanie rekurencyjne:
3. Przenieś n-1 z tymczasowego słupka na słupek „2”
1
2
3
Funkcje rekurencyjne
• Rozwiązanie rekurencyjne:
1
2
3
Funkcje rekurencyjne
• Zauważ, że problem przeniesienia n-1 dysków nie
zależy od dysku n-tego

1
2
3
Funkcje rekurencyjne
• Wieża z Hanoi – złożoność obliczeniowa
• Ile ruchów potrzebnych dla n dysków?
n
2 -1
• Dla n=64: 18446744073709551615 ruchów
• Robiąc jeden na sekundę: 584 miliardów lat (i
nie można się pomylić!)
Funkcje rekurencyjne
• Ciąg Fibbonaciego
F(5)
F(3)
F(4)
F(3)
F(2)
F(1)
F(2)
F(1)
F(0)
F(1)
F(2)
F(0)
F(1)
F(1)
F(0)
Proste rozwiązanie rekurencyjne jest bardzo nieefektywne ze względu
na ogromną ilość powtórzeń obliczeń tej samej wartości
Funkcje rekurencyjne
• Ciąg Fibbonaciego
• Implementacja rekurencyjna „wprost”:
–
–
–
–
Dla n = 30 wykonuje 2692537 kroków obliczeń (3,75 sek)
Dla n = 31 wykonuje 4356617 kroków obliczeń (6,67 sek)
Dla n = 32 wykonuje 7049155 kroków obliczeń (9,83 sek)
Każde zwiększenie n o jeden „prawie podwaja” czas
wykonania
Funkcje rekurencyjne
• Ciąg Fibbonaciego
Modyfikacja:
– Za każdym razem gdy obliczymy jakąś wartość F(i)
zapamiętajmy ją (w słowniku)
– Za każdym razem gdy będziemy chcieli obliczyć F(j)
najpierw sprawdzimy czy wartość ta jest już w
słowniku
• Jeśli wartość jest w słowniku, bierzemy ją, zwracamy i nie
zagnieżdżamy się w rekurencję
• Jeśli wartości nie ma w słowniku, robimy kolejne wejście do
rekurencji.
Funkcje rekurencyjne –
programowanie dynamiczne
• Ciąg Fibbonaciego
• Taka modyfikacja praktycznie redukuje rozwiązanie
do użycia zwyczajnej pętli for.
• W tym przypadku, zastosowanie „programowania
dynamicznego” ma sens tylko dydaktyczny
• Istnieje wiele problemów, które da się w praktyce
rozwiązać tylko w ten sposób!

Podobne dokumenty