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!