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

Z Brain-wiki
 
(Nie pokazano 5 pośrednich wersji utworzonych przez tego samego użytkownika)
Linia 12: Linia 12:
 
*Definicja funkcji to instrukcja złożona, podobna w strukturze do tych, które już znamy - instrukcji warunkowej i pętli.
 
*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''.
 
*Wykonanie definicji funkcji ''nie wiąże się z natychmiastowym wykonaniem zawartego w niej bloku''.
*W definicji funkcji (przykładowej) <tt>x</tt> i <tt>y</tt> 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ć.
+
*W definicji funkcji (przykładowej) <tt>x</tt> i <tt>y</tt> 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ć. Może ich być (niemal) dowolnie wiele, w tym &mdash; zero. W tym ostatnim przypadku piszemy pustą parę nawiasów.
 
*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.
 
*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
 
*Użycie czyli ''wywołanie'' funkcji to wyrażenie postaci
Linia 23: Linia 23:
  
 
*W definicji na ogół występuje (raz lub więcej razy) słowo (instrukcja) <tt>return</tt>. Oznacza ono, że w tym miejscu wykonanie funkcji się kończy - funkcja powraca. Wartość wyrażenia po słowie <tt>return</tt> stanowi wynik zwracany przez funkcję - czyli wartość wyrażenia, będącego wywołaniem funkcji.
 
*W definicji na ogół występuje (raz lub więcej razy) słowo (instrukcja) <tt>return</tt>. Oznacza ono, że w tym miejscu wykonanie funkcji się kończy - funkcja powraca. Wartość wyrażenia po słowie <tt>return</tt> stanowi wynik zwracany przez funkcję - czyli wartość wyrażenia, będącego wywołaniem funkcji.
*Jeśli <tt>return</tt> 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 <tt>None</tt> - która w zasadzie do niczego się specjalnie nie nadaje.
+
*Jeśli <tt>return</tt> 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 <tt>None</tt> &mdash; która w zasadzie do niczego się specjalnie nie nadaje, poza sprawdzeniem, czy mamy do czynienia z właśnie tą wartością.
*''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''':
+
*''funkcja'' w Pythonie (i większości języków programowania) to coś nieco podobnego do funkcji (odwzorowania) w matematyce, ale '''to nie jest to samo pojęcie''':
 
**w Pythonie wywołanie funkcji może mieć skutki uboczne;
 
**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.
 
**wynik funkcji, w tym skutki uboczne, może zależeć nie tylko od argumentów wywołania.
Linia 82: Linia 82:
 
Funkcja może być  
 
Funkcja może być  
  
 +
*zeroargumentowa &mdash; wówczas zarówno w definicji, jak i w wywołaniu po nazwie występuje pusta para nawiasów,
 
*jednoargumentowa (jak powyższa <tt>podwoj</tt>),  
 
*jednoargumentowa (jak powyższa <tt>podwoj</tt>),  
 
*dwuargumentowa (jak przykładowa),
 
*dwuargumentowa (jak przykładowa),
Linia 95: Linia 96:
 
→ 3
 
→ 3
 
</source>
 
</source>
 +
 +
Parametry z wartościami domyślnymi muszą występować na końcu listy parametrów.
 +
*o zmiennej liczbie argumentów, ale bez wartości domyślnych, np.:
 +
 +
<source lang=python>
 +
def ile(*args):
 +
    return len(args)
 +
</source>
 +
 +
Działa to tak: <tt>'*'</tt> postawiona przed nazwą argumentu oznacza, że wszystkie (ew. dalsze) argumenty
 +
zostaną zebrane w jedną listę, która dostępna jest wewnątrz funkcji pod nazwą, jaką postawiliśmy po gwiazdce. W powyższym przykładzie, funkcja <tt>ile</tt> zwraca jako swój wynik po prostu liczbę argumentów, z jakimi funkcja została wywołana. Operator <tt>'*'</tt> nie ma tu wiele wspólnego z mnożeniem. Odróżniamy go od mnożenia po tym, że po jego lewej stronie nie stoi żaden czynnik. Ten sam operator może wystąpić również w roli poniekąd odwrotnej, np.:
 +
 +
<source lang=python>
 +
lista = [*range(5)]
 +
print(*lista)
 +
→ 0 1 2 3 4
 +
</source>
 +
 +
W pierwszej linii, gwiazdka niejako ,,rozwija" sekwencję <tt>range(5)</tt> w ciąg wartości (kolejnych liczb) wstawionych pod operator <tt>[...]</tt>; w linii drugiej, <tt>lista</tt> jest również ,,rozpakowana" w
 +
ciąg oddzielnych argumentów wywołania funkcji <tt>print</tt> &mdash; sprawdź, że wynik <tt>print(lista)</tt> wyglądałby nieco inaczej.
  
 
=Ć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?
+
 
 +
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?
 +
 
 +
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>.
 +
 
 +
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>.
  
 
----
 
----
  
[[PPy3/SekwencjeIIteracja|poprzednie]] | [["Programowanie w Pythonie3"|strona główna]] | [[PPy3/SłownikiIZbiory|dalej]]
+
[[PPy3/SekwencjeIIteracja|poprzednie]] | [["Programowanie z Pythonem3"|strona główna]] | [[PPy3/Kolekcje|dalej]]
  
 
[[Użytkownik:RobertJB|RobertJB]] ([[Dyskusja użytkownika:RobertJB|dyskusja]]) 16:10, 30 cze 2016 (CEST)
 
[[Użytkownik:RobertJB|RobertJB]] ([[Dyskusja użytkownika:RobertJB|dyskusja]]) 16:10, 30 cze 2016 (CEST)

Aktualna wersja na dzień 13:32, 10 maj 2023

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ć. Może ich być (niemal) dowolnie wiele, w tym — zero. W tym ostatnim przypadku piszemy pustą parę nawiasów.
  • 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, poza sprawdzeniem, czy mamy do czynienia z właśnie tą wartością.
  • funkcja w Pythonie (i większości języków programowania) to coś nieco podobnego do funkcji (odwzorowania) 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ć

  • zeroargumentowa — wówczas zarówno w definicji, jak i w wywołaniu po nazwie występuje pusta para nawiasów,
  • 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

Parametry z wartościami domyślnymi muszą występować na końcu listy parametrów.

  • o zmiennej liczbie argumentów, ale bez wartości domyślnych, np.:
def ile(*args):
    return len(args)

Działa to tak: '*' postawiona przed nazwą argumentu oznacza, że wszystkie (ew. dalsze) argumenty zostaną zebrane w jedną listę, która dostępna jest wewnątrz funkcji pod nazwą, jaką postawiliśmy po gwiazdce. W powyższym przykładzie, funkcja ile zwraca jako swój wynik po prostu liczbę argumentów, z jakimi funkcja została wywołana. Operator '*' nie ma tu wiele wspólnego z mnożeniem. Odróżniamy go od mnożenia po tym, że po jego lewej stronie nie stoi żaden czynnik. Ten sam operator może wystąpić również w roli poniekąd odwrotnej, np.:

lista = [*range(5)]
print(*lista)
 0 1 2 3 4

W pierwszej linii, gwiazdka niejako ,,rozwija" sekwencję range(5) w ciąg wartości (kolejnych liczb) wstawionych pod operator [...]; w linii drugiej, lista jest również ,,rozpakowana" w ciąg oddzielnych argumentów wywołania funkcji print — sprawdź, że wynik print(lista) wyglądałby nieco inaczej.

Ć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)