Veľkonočná akcia je tu a s ňou aj extra kredity ZADARMO na náš interaktívny e-learning. Dobij si teraz kredity a posuň sa vo svojej kariére vpred!
Zarábaj až 6 000 € mesačne! Akreditované rekvalifikačné kurzy od 0 €. Viac informácií.

17. diel - Funkcie a výnimky v Pythone

V minulej lekcii, Cykly v Pythone druhýkrát - Výraz pass, break a continue, sme ucelili naše znalosti cyklov ďalšími konštrukciami a kľúčovými slovami pass, break a continue.

V dnešnom Python tutoriále sa naučíme funkcionálny štýl programovania. Ďalej sa pozrieme na jednoduché ošetrovanie chýb programu a vylepšíme si kalkulačku.

Funkcie

Doteraz sme programy písali imperatívne - urob tento príkaz, následne tamten a tak ďalej. Týmto spôsobom je možné písať jednoduché a krátke programy. Väčšie programy by však boli veľmi neprehľadné. Preto prejdeme na ďalšiu programovaciu paradigmu (spôsob, ako niečo naprogramovať) – na funkcionálne programovanie. Náš program si rozdelíme na menšie časti (podproblémy), ktoré vyriešime samostatne. Jednotlivé problémy riešia funkcie. Pre funkcionálny štýl programovania môžeme použiť všetko, čo sme sa doteraz naučili.

Funkcia obvykle prijíma argumenty (dáta, ktoré funkcia spracuje) a niečo vracia, napríklad výslednú hodnotu. Nemusí ale tiež vracať nič - ako napr. funkcia print().

Základné syntax funkcie

Funkcia sa definuje pomocou kľúčového slova def a výslednú hodnotu vracia kľúčovým slovom return. Za def sa píše medzera a potom názov funkcie. Za názov funkcie sa dávajú jednoduché zátvorky, do ktorých sa píšu názvy jednotlivých argumentov. Argumentom funkcie v programovacom jazyku Python je hodnota alebo premenná, ktorú odovzdávame funkciu, aby hodnotu alebo premennú mohla použiť počas svojho vykonávania. Keď funkciu definujeme, špecifikujeme, aké argumenty môže prijať. Potom, keď funkciu voláme, dosadzujeme hodnoty pre tieto argumenty. Funkcia môže byť aj bez argumentov. Na konci prvého riadku sa píše dvojbodka. Telo funkcie sa štandardne odsadzuje:

def power(number):
    number = number ** 2
    return number

Takto vytvorená funkcia power() vracia číslo umocnené na druhú. Napríklad pri zavolaní power(1) vráti 1, pri zavolaní power(2) vráti 4 atď. V praxi to vyzerá nasledovne:

Klikni pre editáciu
  • def power(number):         # number is the argument name
        number = number ** 2
        return number
    
    first_number = power(2)    # 2 is the value passed to the function
    print(first_number)
    • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

    Argumentov môže byť samozrejme aj viac:

    Klikni pre editáciu
    • def product(first_number, second_number, third_number):
          number = first_number * second_number * third_number
          return number
      
      example = product(2, 3, 4)
      print(example)
      • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

      Funkciu môžeme tiež použiť ako argument inej funkcie:

      Klikni pre editáciu
      • def product(first_number, second_number, third_number):
            number = first_number * second_number * third_number
            return number
        
        print(product(2, 3, 4))  #  we use our function as an argument of the print() function
        • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

        Druhy argumentov funkcie

        V Pythone máme dva druhy argumentov:

        • pozičné,
        • kľúčové.

        Pozičné argumenty

        Pozičné argumenty sme videli vyššie. Na ich pozícii sa dosadí argument na rovnakej pozícii pri volaní funkcie. Tieto argumenty nemajú danú základnú hodnotu. Ich syntax je jednoduchá: argument_name.

        Kľúčové argumenty

        Kľúčové argumenty majú už vopred nastavenú hodnotu, ktorú je možné zmeniť. Na rozdiel od argumentov pozičných sú tie kľúčové označené kľúčovým slovom (majú svoj názov). Tieto argumenty nemusia byť pri volaní funkcie zadané v poradí, v ktorom sú deklarované. Navyše ich nemusíme pri volaní funkcie inicializovať (určiť ich hodnotu). V takom prípade sa použije ich východisková hodnota. Syntax vyzerá takto: argument_name=value.

        Všetky pozičné argumenty musia byť deklarované pred tými kľúčovými!

        Ako príklad si ukážme vylepšenú verziu funkcie na výpočet mocniny:

        Klikni pre editáciu
        • def power(base, exponent=2):    # base is a positional argument, exponent is a keyword argument
              result = base ** exponent
              return result
          
          print(power(2))
          • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

          Prvý argument je pozičný, druhý je kľúčový. Teraz môžeme volať power(1), power(1, exponent=2), prípadne power(1, 2) a dostaneme rovnaký výsledok. Navyše môžeme umocniť 3 na 4 - power(3, exponent=4). To už však musíme hodnotu exponentu špecifikovať:

          Klikni pre editáciu
          • def power(base, exponent=2):
                result = base ** exponent
                return result
            
            print(power(3, exponent=4))
            • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

            Všeobecne sa pozičné argumenty zapisujú ako args a kľúčové ako kwargs.

            Zvláštnou vlastnosťou Pythona je to, že kľúčový argument (kwarg) môžeme zadávať aj ako obyčajný argument (arg), ak jeho poradie zodpovedá deklarácii funkcie.

            Ako príklad si ešte raz ukážme našu funkciu power():

            Klikni pre editáciu
            • def power(base, exponent=2):    # base is a positional argument, exponent is a keyword argument
                  result = base ** exponent
                  return result
              
              print(power(3, 4))               # here we called the keyword argument exponent as a regular positional argument
              • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

              Operátor *

              V Pythone operátor * neslúži len pre násobenie. Keď ho použijeme v definícii funkcie, umožňuje nám zachytávať premenný počet pozičných argumentov. Týmto spôsobom môžeme flexibilne pracovať s rôznym množstvom vstupných hodnôt. Uveďme si príklad:

              def some_function(*positional_arguments):
                  pass

              V tomto prípade sa všetky zadané pozičné argumenty odovzdané funkcii zhromaždia do n-tice (dátový typ podobný zoznamu) s názvom positional_arguments. S touto n-ticou môžeme ďalej pracovať, napríklad ju prechádzať pomocou cyklu for:

              Klikni pre editáciu
              • def product(*numbers):
                    result = 1
                    for number in numbers:
                        result = result * number
                    return result
                
                print(product(2, 3, 4, 5))
                • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

                Keď teda zavoláme funkciu product(2, 3, 4, 5), všetky štyri čísla sú zbalené do n-tice numbers a v tele funkcie sú následne prístupné ako numbers[0], numbers[1], numbers[2] a numbers[3]. N-tici potom jednoducho prejdeme pomocou cyklu for. Vďaka tejto vlastnosti môžeme funkciu product() volať s ľubovoľným počtom čísel.

                Keď použijeme * v definícii funkcie bez nasledujúceho mena premennej, hovoríme tým, že funkcia smie od tohto miesta ďalej prijímať iba kľúčové argumenty. Inými slovami, všetky argumenty za * musia byť pri volaní funkcie špecifikované ako kľúčové.

                Ukážme si to na konkrétnom príklade:

                def my_function(*, first_keyword_arg=1, second_keyword_arg=1):
                    print(first_keyword_arg, second_keyword_arg)

                V tomto prípade nám funkcia nedovolí použiť pozičné argumenty. Musíme ich špecifikovať ako kľúčové argumenty:

                my_function(first_keyword_arg=5, second_keyword_arg=10)  # output: 5 10
                
                # The following call would raise an error:
                # my_function(5, 10)   # TypeError: my_function() takes 0 positional arguments but 2 were given

                Ak chceme použiť zápis s operátorom * pre kľúčové argumenty, napíšeme dve hviezdičky.

                Rekurzia

                Pojem rekurzia označuje zápis kódu, kedy funkcia volá samu seba. Rekurziu môžeme použiť napríklad na výpočet faktoriálu. Uveďme si príklad:

                def factorial(number):
                    if number > 0:
                        return factorial(number - 1) * number
                    else:
                        return 1

                Pri rekurzii si musíme dať pozor, aby sa funkcia niekedy ukončila. Inak program spadne kvôli pretečeniu zásobníka. Rekurzie podrobne vysvetľujeme pri algoritme faktoriálu.

                Typovanie funkcií

                Pokiaľ chceme explicitne deklarovať typ parametrov funkcií a ich návratové hodnoty, použijeme na to operátor ->. Pozrime sa na príklad:

                def generate_hello(name: str) -> str:      #  the return value of the function will be str
                    return "Hello, " + name + "!"

                V rozsiahlejších projektoch je typovanie obzvlášť užitočné pre udržanie kvality a konzistencie kódu. Uľahčuje spoluprácu viacerých vývojárov a pomáha pri zachovaní dobrej architektúry.

                Mimochodom, podobne postupujeme aj u premenných. Len operátor je iný. Pokiaľ chceme explicitne deklarovať typ premennej, použijeme na to dvojbodkový operátor ::

                text: str = "Hello World!"

                Teraz je jasne povedané, že text je typu str. V tomto prípade to možno spoznať podľa hodnoty "Hello World!", Takže je tu také označenie trochu nadbytočné. Avšak v programoch v praxi býva veľa miest, kde to už tak jasné nie je. Potom má deklarovanie typu zmysel.

                Úprava výstupu funkcie print()

                Teraz sa naučíme upraviť si funkciu print(). Už sme sa s tým čiastočne stretli v predchádzajúcich lekciách, keď sme upravovali, čím funkcia print() ukončí riadok. Teraz sa na ňu pozrieme podrobnejšie. Najprv sa zameriame na jej dva kľúčové argumenty:

                • sep – Argument udáva medzery medzi jednotlivými prvkami (pozičnými argumentmi). Normálne je nastavený na medzeru (" ").
                • end – Tento argument definuje, čím sa zápis ukončí. Normálne sa tak deje znakom nového riadka ("\n").

                Poďme si to vyskúšať na príklade:

                Klikni pre editáciu
                • print(1, 2, 3, "a", sep="-")
                  
                  print("No new line", end=" ")
                  print("will appear", end=" ")
                  • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

                  Ošetrenie chýb

                  Vo väčšine nami doteraz vytvorených programov sme užívateľovi umožnili spáchať chybu pri číselnom vstupe. Pokiaľ by teda užívateľ zadal namiesto čísla napr. písmeno, náš program by spadol.

                  Teraz si teda ukážeme, ako takéto chyby ošetriť. Ošetrenie sa vykonáva pomocou bloku tryexcept:

                  try:
                      #  Block of commands
                  except first_exception_name:
                      #  Block of commands
                  except another_exception_name:
                      #  Block of commands
                  else:
                      #  This block of commands will execute if no errors occur.
                  finally:
                      #  Block of commands that will always execute.

                  Ak chceme zachytiť aj chybovú správu, musíme kód upraviť takto:

                  except exception_name as error:
                      #  The exception text is stored in the variable 'error'.

                  Chybám sa v Pythone (a v objektových jazykoch všeobecne) hovorí výnimky. Tie základné sú nasledujúce:

                  • SyntaxError – chyba je v zdrojovom kóde,
                  • ZeroDivisionError – pokus o delenie nulou,
                  • TypeError – nesprávne použitie dátových typov, napr. sčítanie reťazca a čísla,
                  • ValueError – nesprávna hodnota.

                  Všetky výnimky nájdeme v dokumentácii Pythona.

                  Ukážme si jednoduchý príklad, ktorý využije všetky kľúčové slová bloku tryexcept:

                  go_on = True
                  while go_on:
                      try:
                          dividend = float(input("Enter the number you want to divide:  "))
                          divisor  = float(input("Enter the number you want to divide by:  "))
                  
                          result = dividend / divisor
                  
                      except ZeroDivisionError:
                          print("Division by zero is not allowed!")
                  
                      except ValueError:
                          print("An invalid value was entered!")
                  
                      else:
                          print(f"The result of the division is: {result}")
                  
                      finally:
                          leave = input("Do you want to exit the program? (yes/no):  ").lower()
                          if leave == "yes":
                              go_on = False

                  Kód si vysvetlíme. V tomto kóde sa program užívateľa spýta, ktoré čísla chce deliť. Pokiaľ užívateľ skúsi deliť nulou, program zachytí a vyhodí chybovú správu. Rovnako tak dôjde k zachyteniu chyby v prípade, že používateľ vloží niečo iné ako číslo. Blok else sme použili na výpis výsledku delenia v prípade, že nedôjde k výnimke. Blok finally potom umožňuje užívateľovi opustiť cyklus a ukončiť program.

                  Vylepšenie kalkulačky

                  Teraz máme dosť znalostí na to, aby sme mohli znova vylepšiť našu kalkulačku. Najprv si pripomeňme jej doterajší kód:

                  print("Welcome to our calculator/T}")
                  go_on = "yes"
                  while go_on == "yes":
                      a = float(input("Enter first number:  "))
                      b = float(input("Enter second number:  "))
                      print("Choose one of the following operations: ")
                      print("1 - addition")
                      print("2 - subtraction")
                      print("3 - multiplication")
                      print("4 - division")
                      option = int(input())
                      result = 0.0
                      match option:
                          case 1:
                              result = a + b
                          case 2:
                              result = a - b
                          case 3:
                              result = a * b
                          case 4:
                              if b != 0:
                                  result = a / b
                              else:
                                  print("Division by zero is not allowed!")
                                  result = "N/A"
                  
                      if 0 < option < 5:
                          print(f"Result: {result}")
                      else:
                          print("Invalid option")
                      go_on = input("Would you like to make another calculation? [yes/no]: ")
                  print("Thank you for using our calculator.")

                  Pusťme sa do vylepšovania kódu. Najprv naprogramujeme "užívateľovi vzdornú" funkciu na získanie čísla zo vstupu:

                  def get_number(prompt_text, error_text):
                      invalid_input = True
                      while invalid_input:
                          try:
                              number = float(input(prompt_text))
                              invalid_input = False
                          except ValueError:
                              print(error_text)
                  
                      return number

                  Program sa tak dlho opakuje v cykle, kým od užívateľa nezíska správny vstup. Riadok s float() prevedie reťazec na desatinné číslo.

                  Ďalej si naprogramujeme funkciu, ktorá umožní zadať iba yes a no:

                  def another_example():
                      invalid_response = True
                      while invalid_response:
                          answer = input("Would you like to make another calculation? [yes/no]: ").lower()
                          if answer in ["yes", "no"]:
                              invalid_response = False
                          else:
                              print("Please answer 'yes' or 'no'.")
                      return answer == "yes"  #  The function returns True when the string "yes" is stored in the answer variable, otherwise it returns False.

                  Ďalej musíme ošetriť, čo sa stane po voľbe operácie. Užívateľ by mohol zadať napríklad číslo mimo interval <1;4> a tým zvoliť neexistujúcu operáciu. Prípadne zadať čísla 5 a 0 a potom zvoliť delenie. Náš program by potom skončil s výnimkou ZeroDivisionError. Musíme sa teda o tieto potenciálne chyby postarať. Je tiež nevhodné, aby funkcia tlačila výsledok, funkcia má vždy vracať hodnotu:

                  def perform_operation(a, b):
                      operation = 0
                      while operation not in [1, 2, 3, 4]:
                          print("1 - addition")
                          print("2 - subtraction")
                          print("3 - multiplication")
                          print("4 - division")
                  
                          #  To avoid handling user input again when selecting an operation, we'll use our already created function here
                          #  We'll cast its output (of type float) to int
                          operation = int(get_number("Choose one of the following operations:  ", "Invalid input. Please enter a number..."))
                  
                          if operation == 4 and b == 0:
                              print("Division by zero is not allowed!")
                              operation = 0  #  Reset operation due to division by zero
                  
                          elif operation < 1 or operation > 4:
                              print("Invalid choice. Please enter a number corresponding to the selected operation.") #  Invalid input handling
                  
                      match operation:
                          case 1:
                              return a + b
                          case 2:
                              return a - b
                          case 3:
                              return a * b
                          case 4:
                              return a / b

                  Hlavný cyklus programu sa s našimi novými funkciami značne zjednoduší:

                  print("Calculator\n")
                  go_on = True
                  
                  while go_on:
                      first_number = get_number("Enter first number: ", "Invalid number!\n")
                      second_number = get_number("Enter second number: ", "Invalid number!\n")
                      calculation_result = perform_operation(first_number, second_number)
                      print(f"Result: {calculation_result}")
                      go_on = another_example()
                  
                  print("Thank you for using our calculator.")
                  input()

                  Celý kód sme rozdelili do prehľadných a jednoduchých blokov. Prípadné úpravy v kóde potom budú výrazne jednoduchšie. Celý kód je tiež oveľa čitateľnejší. Toto je podstata funkcionálnej paradigmy !

                  V budúcej lekcii, Matematické funkcie v Pythone a knižnica math, sa pozrieme na užitočné matematické funkcie.


                   

                  Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

                  Stiahnuť

                  Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

                  Stiahnuté 15x (1.37 kB)
                  Aplikácia je vrátane zdrojových kódov v jazyku Python

                   

                  Ako sa ti páči článok?
                  Pred uložením hodnotenia, popíš prosím autorovi, čo je zleZnakov 0 z 50-500
                  Predchádzajúci článok
                  Cykly v Pythone druhýkrát - Výraz pass, break a continue
                  Všetky články v sekcii
                  Základné konštrukcie jazyka Python
                  Preskočiť článok
                  (neodporúčame)
                  Matematické funkcie v Pythone a knižnica math
                  Článok pre vás napísal gcx11
                  Avatar
                  Užívateľské hodnotenie:
                  35 hlasov
                  (^_^)
                  Aktivity