PPy3/Funkcje: Różnice pomiędzy wersjami

Z Brain-wiki
Linia 98: Linia 98:
 
=Ćwiczenia=
 
=Ćwiczenia=
  
#Napisz funkcję <tt>pierwiastki(a, b, c)</tt>, która wypisuje na ekran (za pomocą wywołania <tt>print</tt>) pierwiastki równania kwadratowego o wspołczynnikach ''a'', ''b'' i ''c'': <tt>a * x**2 + b * x + c == 0</tt>. W przypadku, gdy pierwiastków nie ma, wypisuje komunikat ''Równanie nie ma pierwiastków.'' W przypadku, gdy ''a=0'', wypisuje komunikat ''Błędne dane: a==0'' i kończy działanie.
+
1. Napisz funkcję <tt>pierwiastki(a, b, c)</tt>, która wypisuje na ekran (za pomocą wywołania <tt>print</tt>) pierwiastki równania kwadratowego o wspołczynnikach ''a'', ''b'' i ''c'': <tt>a * x**2 + b * x + c == 0</tt>. W przypadku, gdy pierwiastków nie ma, wypisuje komunikat ''Równanie nie ma pierwiastków.'' W przypadku, gdy ''a=0'', wypisuje komunikat ''Błędne dane: a==0'' i kończy działanie.
#Napisz analogiczną funkcję, która zamiast bezpośrednio wypisywać rozwiązania, zwraca je jako wynik swojego działania. Wypisaniem ich na ekran zajmuje się odrębna instrukcja. W przypadku, gdy pierwiastków nie ma, zwraca wartość <tt>None</tt>. Nie sprawdzaj warunku ''a!=0'' - co się dzieje, gdy nie jest spełniony przez argumenty wywołania funkcji?
+
 
#Napisz funkcję <tt>silnia(n)</tt>, która oblicza i zwraca wartość silni: <tt>n! := 1 * 2 * 3 * ... (n - 1) * n</tt>. Uwzględnij, że przyjmuje się że <tt>0! = 1</tt>, natomiast dla liczb ujemnych silnia nie jest określona - co można zasygnalizować zwracając jako wynik <tt>None</tt>. Użyj pętli <tt>for</tt> i funkcji <tt>range</tt>.
+
2. Napisz analogiczną funkcję, która zamiast bezpośrednio wypisywać rozwiązania, zwraca je jako wynik swojego działania. Wypisaniem ich na ekran zajmuje się odrębna instrukcja. W przypadku, gdy pierwiastków nie ma, zwraca wartość <tt>None</tt>. Nie sprawdzaj warunku ''a!=0'' - co się dzieje, gdy nie jest spełniony przez argumenty wywołania funkcji?
#Funkcję silnia można zdefiniować w sposób rekurencyjny - za pomocą następujących warunków:
+
 
**<tt>n! == None</tt> dla <tt>n < 0</tt>
+
3. Napisz funkcję <tt>silnia(n)</tt>, która oblicza i zwraca wartość silni: <tt>n! := 1 * 2 * 3 * ... (n - 1) * n</tt>. Uwzględnij, że przyjmuje się że <tt>0! = 1</tt>, natomiast dla liczb ujemnych silnia nie jest określona - co można zasygnalizować zwracając jako wynik <tt>None</tt>. Użyj pętli <tt>for</tt> i funkcji <tt>range</tt>.
**<tt>0! == 1</tt>
+
 
**<tt>n! == n * (n - 1)!</tt>
+
4. Funkcję silnia można zdefiniować w sposób rekurencyjny - za pomocą następujących warunków:
 +
<blockquote>
 +
<tt>n! == None</tt> dla <tt>n < 0</tt><br>
 +
<tt>0! == 1</tt><br>
 +
<tt>n! == n * (n - 1)!</tt>
 +
</blockquote>
 
Napisz kod funkcji <tt>silnia(n)</tt> realizujący powyższą definicję. Porównaj działanie tego kodu z realizacją tej funkcji z poprzedniego przykładu dla dużych wartości <tt>n</tt>.
 
Napisz kod funkcji <tt>silnia(n)</tt> realizujący powyższą definicję. Porównaj działanie tego kodu z realizacją tej funkcji z poprzedniego przykładu dla dużych wartości <tt>n</tt>.
  

Wersja z 13:19, 20 lis 2016

Funkcje

Gdy raz wymyślimy jakiś sprytny algorytm, to nie ma co go za każdym razem odkrywać na nowo. Żeby było łatwiej pisać raz, a korzystać wielokrotnie - wymyślono funkcje.

Definiowanie funkcji

def funkcja(x, y):
    BLOK INSTRUKCJI
  • Definicja funkcji to instrukcja złożona, podobna w strukturze do tych, które już znamy - instrukcji warunkowej i pętli.
  • Wykonanie definicji funkcji nie wiąże się z natychmiastowym wykonaniem zawartego w niej bloku.
  • W definicji funkcji (przykładowej) x i y to parametry formalne; nie mają one w tym momencie określonych wartości, są miejscami do wypełnienia konkretnymi wartościami, gdy funkcję postanowimy użyć.
  • Wykonanie definicji funkcji polega na nadaniu znaczenia jej nazwie, która odtąd będzie oznaczała ciąg instrukcji stanowiących wewnętrzny blok.
  • Użycie czyli wywołanie funkcji to wyrażenie postaci
funkcja(x, y)

gdzie x i y mają już konkretne wartości (w tym miejscu mogą stać również wyrażenia złożone), które będą użyte w instrukcjach stanowiących definicję.

  • W definicji na ogół występuje (raz lub więcej razy) słowo (instrukcja) return. Oznacza ono, że w tym miejscu wykonanie funkcji się kończy - funkcja powraca. Wartość wyrażenia po słowie return stanowi wynik zwracany przez funkcję - czyli wartość wyrażenia, będącego wywołaniem funkcji.
  • Jeśli return nie ma, albo nie ma po nim wartości zwracanej, albo wykonanie funkcji kończy się ,,wypadnięciem" przez koniec bloku, wartością zwracaną jest None - która w zasadzie do niczego się specjalnie nie nadaje.
  • funkcja w Pythonie (i większości języków programowania) to coś nieco podobnego do funkcji w matematyce, ale to nie jest to samo pojęcie:
    • w Pythonie wywołanie funkcji może mieć skutki uboczne;
    • wynik funkcji, w tym skutki uboczne, może zależeć nie tylko od argumentów wywołania.

Skutkami ubocznymi wywołania nazywamy jakiekolwiek efekty tej instrukcji, które nie sprowadzają się do wartości zwracanej. A więc, zmianę wartości innych zmiennych, czy np. wysłanie jakichś danych siecią, lub wypisanie czegoś na ekran.

  • Funkcja może być wartością zmiennej; inaczej mówiąc, funkcja może być znana pod dodatkowymi nazwami (aliasami), może być włożona do listy na którąś z jej pozycji itp.
ff = funkcja
...
wynik = ff(x)
  • ,,Oryginalna" nazwa funkcji, czyli występująca w jej definicji, jest jednak w pewnym sensie uprzywilejowana.
  • Zmienne (nazwy) powołane do życia wewnątrz funkcji są lokalne; ich wartości ,,żyją" tylko póki wykonuje się funkcja.
  • Zmienne lokalne powielające nazwy ,,zewnętrzne" względem funkcji przesłaniają te zewnętrzne. Chyba, że użyjemy deklaracji global:
x = 1
def podwojx():  # to nie zadziała:
    x = x * 2
podwojx()
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-3-6edd575e5cda> in <module>()
----> 1 podwojx()

<ipython-input-1-1da635f42ffa> in podwojx()
      1 def podwojx():
----> 2     x *= 2
      3 

UnboundLocalError: local variable 'x' referenced before assignment

Jak widzimy, komunikat o błędzie pojawił się dopiero w wyniku wywołania błędnej funkcji.

x = 1
def podwojx():  # to zadziała - co nie znaczy, że jest mądre...
    global x
    x = x * 2
podwojx()
print x
 2

Należy unikać takich sztuczek, jak powyżej; jeśli już, to:

def podwoj(x):
    return 2 * x
liczba = 1
print podwoj(liczba)
 2

Wskazówka: każde użycie deklaracji global w programie powinno być dobrze uzasadnione. Jeżeli używamy jej więcej niż sporadycznie, to coś jest nie tak.

Funkcja może być

  • jednoargumentowa (jak powyższa podwoj),
  • dwuargumentowa (jak przykładowa),
  • trzy-, cztero-, ... itd.
  • o zmiennej liczbie argumentów, z wartościami domyślnymi dla brakujących:
def dodaj(x, y=1):
    return x + y
dodaj(2, 3)
 5
dodaj(2)
 3

Ćwiczenia

1. Napisz funkcję pierwiastki(a, b, c), która wypisuje na ekran (za pomocą wywołania print) pierwiastki równania kwadratowego o wspołczynnikach a, b i c: a * x**2 + b * x + c == 0. W przypadku, gdy pierwiastków nie ma, wypisuje komunikat Równanie nie ma pierwiastków. W przypadku, gdy a=0, wypisuje komunikat Błędne dane: a==0 i kończy działanie.

2. Napisz analogiczną funkcję, która zamiast bezpośrednio wypisywać rozwiązania, zwraca je jako wynik swojego działania. Wypisaniem ich na ekran zajmuje się odrębna instrukcja. W przypadku, gdy pierwiastków nie ma, zwraca wartość None. Nie sprawdzaj warunku a!=0 - co się dzieje, gdy nie jest spełniony przez argumenty wywołania funkcji?

3. Napisz funkcję silnia(n), która oblicza i zwraca wartość silni: n! := 1 * 2 * 3 * ... (n - 1) * n. Uwzględnij, że przyjmuje się że 0! = 1, natomiast dla liczb ujemnych silnia nie jest określona - co można zasygnalizować zwracając jako wynik None. Użyj pętli for i funkcji range.

4. Funkcję silnia można zdefiniować w sposób rekurencyjny - za pomocą następujących warunków:

n! == None dla n < 0
0! == 1
n! == n * (n - 1)!

Napisz kod funkcji silnia(n) realizujący powyższą definicję. Porównaj działanie tego kodu z realizacją tej funkcji z poprzedniego przykładu dla dużych wartości n.


poprzednie | strona główna | dalej

RobertJB (dyskusja) 16:10, 30 cze 2016 (CEST)