Funkcje mogą wywoływać inne funkcje

Musimy zrozumieć jedną bardzo ważną rzecz. Każdą funkcję, którą tworzymy możemy wywołać z ciała innej funkcji. Jest to jedna z najważniejszych metod, jakich używa programista, aby podzielić dany, duży problem na mniejsze podproblemy. Ten proces nazywa się dekompozycją funkcyjną. .. functional decomposition

Poniżej znajduje się prosty przykład takiej dekompozycji z użyciem dwóch funkcji. Pierwsza z nich nazywa się square i oblicza ona po prostu kwadrat danej liczby. Druga z funkcji sum_of_squares używa funkcji square do obliczenia sumy trzech liczb podniesionych wcześniej do kwadratu.

(sumofsquares)

Pomimo że jest to dość prosta idea, w praktyce ten przykład pokazuje kilka bardzo istotnych koncepcji programowania w Pythonie. Wśród nich są takie zagadnienia jak lokalne i globalne zmienne oraz przekazywanie parametrów. Przechodząc krok po kroku przez ten przykład, codelens pogrubi linię 1 i 5, tam gdzie zdefiniowane są funkcje. Ciało funkcji square nie będzie interpretowane dopóki funkcja nie zostanie wywołana z sum_of_squares po raz pierwszy (linia 6). Zauważ też, że kiedy wywoływana jest funkcja square pojawiają się dwie grupy zmiennych lokalnych, jedna dla funkcji square a druga dla sum_of_squares. Uruchamiając kod w codelens zobaczycie, że x i y są zmiennymi lokalnymi w obu funkcjach, mogą też trzymać różne wartości. Pokazuje to, że nawet mając tę samą nazwę są one kompletnie innymi zmiennymi.

Teraz spójrzmy na inny przykład, w którym też użyjemy dwóch funkcji. Przykład ten ilustruje inną ważną technikę w programowaniu, nazywaną uogólnieniem. Załóżmy, że chcielibyśmy napisać funkcję, która rysuje kwadrat. Aby uogólnić ten problem należy zauważyć, że kwadrat to szczególna postać prostokąta.

Aby narysować prostokąt musimy mieć możliwość wywołania funkcji z innymi argumentami dla wysokości i szerokości. Nie możemy powtórzyć tej samej czynności 4 razy, ponieważ boki nie są równe. Ale można zauważyć, że sekwencja rysowania dolnego i prawego boku jest identyczna z sekwencją rysowania góry i lewego boku. Tak więc koniec końców dostaniemy ten raczej przyjemny kod rysujący prostokąty.

def draw_rectangle(t, w, h):
    """Uzyj zolwia t do narysowania prostokata o szerokosci w i wysokosci h."""
    for i in range(2):
        t.forward(w)
        t.left(90)
        t.forward(h)
        t.left(90)

Jednoliterowe nazwy parametrów wybrane zostały celowo, aby upewnić się, że nie zostaną one źle zrozumiane. Przy pisaniu prawdziwych programów, jak już nabierzecie nieco doświadczenia, będziemy nalegać na lepsze nazewnictwo zmiennych od tego tutaj. Chodzi po prostu o to, że program „nie rozumie” tego, że chcemy narysować prostokąt, albo tego, że owe parametry reprezentują szerokość i wysokość. Takie koncepty jak prostokąt, szerokość, wysokość są zrozumiałe dla ludzi. Programy czy komputery ich nie rozumieją.

Myśleć jak programista (Thinking like a computer scientist) uczy nas też znajdywania relacji i zauważania wzorców. W kodzie powyżej do pewnego stopnia posłużyliśmy się czymś takim. Nie narysowaliśmy po prostu czterech boków. Zamiast tego zauważyliśmy, że możemy narysować prostokąt jako dwie osobne połowy i użyliśmy pętli, aby dwukrotnie powtórzyć ten wzorzec.

Teraz możemy zauważyć, że kwadrat to specjalny rodzaj prostokąta. Używa on po prostu tej samej wartości dla szerokości i wysokości. Jako, że mamy już funkcję rysującą prostokąt, możemy jej użyć do rysowania kwadratu.

def drawSquare(tx, sz):        # nowa wersja drawSquare
    draw_rectangle(tx, sz, sz)

A poniżej jest cały program razem z niezbędnym kodem wstępnym.




(ch04_3)

Kilka punktów wartych zapamiętania:

Póki co nie do końca może być jasne, dlaczego warto tworzyć te wszystkie nowe funkcje. Naprawdę powodów jest sporo, ale tutaj zilustrowaliśmy trzy:

  1. Tworzenie nowych funkcji daje nam możliwość grupowania wyrażeń. Funkcje mogą upraszczać program poprzez ukrywanie skomplikowanych obliczeń za pojedynczą komendą. Funkcja (wraz ze swoją nazwą) może odwzorować twój teoretyczny podział problemu na kawałki, może odwzorować poziom abstrakcji zagadnienia.
  2. Tworzenie funkcji może zmniejszyć ilość linii programu poprzez pozbycie się powtarzających się części kodu.
  3. Czasem można zdefiniować funkcję pozwalającą na rozwiązanie konkretnego zagadnienia poprzez użycie nieco bardziej ogólnego rozwiązania.

Lab

  • Rysowanie koła Ten przykład przeprowadzi cię przez rozwiązanie prostego problemu związanego z rysowaniem koła z użyciem żółwia.
Następna część - Przepływ instrukcji - podsumowanie