Funkce a třídy

Programování v GIS 2

Jan Caha

2025-03-24

Programovací paradigmata

  • většina jazyků nestojí striktně na jednom paradigmatu, ale využívá jich vícero

  • imperativní (kód popisuje, co se bude dít)

    • procedurální programování (procedury, které ze vzájemně volají)
    • objektové programování (objekty - data a operace s nimi asociované)
    • většina jazyků - např. Python, R, C++
  • deklarativní (kód popisuje požadovaný výsledek)

    • funkcionální, logické a reaktivní
    • např. jazyk SQL, ale i funkcionální přístupy v Pythonu a R

Python

  • pro běžné použití kombinujeme obvykle procedurální a objektový přístup
  • procedurální přístup - funkce, které mají parametry
  • objektový přístup - objekty, které mají metody (funkce asociované s objektem) a atributy (proměnné objektu)
  • není problém s kombinací, viz cvičení (GDAL/OGR má objekty, my si k nim píšeme funkce)

Funkce

  • dělí kód na dílčí logické bloky, které mohou být znovu použitelné
  • měly by dělat jednu věc a pouze jednu věc
  • délka by neměla být velká (aby bylo možné tělo funkce logicky přečíst a pochopit)
  • snaha navrhovat funkce spíše obecně než specificky

Funkce příklad

def fn(a: str, b: int, c: float = 0.5) -> float: ...
  • funkce se třemi proměnnými
    • první dvě povinné
    • třetí nepovinná s výchozí hodnotou

Pozor

Proměnné s výchozí hodnotou musí být až za proměnnými bez výchozí hodnoty. Nelze mít proměnnou bez výchozí hodnoty za proměnnou s výchozí hodnotou funkce by nebyla validní a Python by vykazoval chybu při snaze takovou funkce načíst.

  • funkce vrací float
  • mohou existovat funkce bez návratové hodnoty None
  • nezapomínat na typování parametrů a návratové hodnoty

Funkce obecná specifická

# specifické
def vynasob_dvema(a: float) -> float:
    return a * 2


# obecné
def vynasob(a: float, b: float) -> float:
    return a * b

Tvorba upravené funkce (předefinování parametrů)

  • funkce partial z modulu functools
  • vytvoří novou funkci, která má některé parametry přednastavené a uloží ji do proměnné
from functools import partial

# zadáme funkci a potom parametr(y) které chceme předdefinovat
multiply_hodnotu_dvema = partial(vynasob, b=2)
hodnota = multiply_hodnotu_dvema(3)

Objekty

  • třída je šablona objektu, jednotlivý objekt je pak instancí třídy
  • objekt je prvek, které má vlastní informace a s kterými můžeme vykonávat operace
  • metody, vlastnosti (property) a atributy
  • složitost se může různit

Objekty detaily

  • první parametr metody je vždy self (označení instance objektu)
  • atributy i metody mohou být veřejné nebo soukromé (neměly by být přímo dostupné zvenčí třídy) – v Pythonu se to řeší konvencí, soukromé atributy a metody začínají podtržítkem (např. _atribut), tyto metody a atributy nebudou nápovědy v IDE navrhovat a programátor by se měl ideálně jejich použití vyhnout
  • magické metody objektů (např. __init__, __str__, __add__, __eq__ a další) a jejich použití
  • vlastnost (property), mohou být buď statické (přímo hodnota objektu) nebo dynamické (metoda s dekorátorem @property)

Metody objektu

  • metody objektu jsou funkce, které jsou součástí objektu, první parametr je vždy self
  • metody mohou být i tzv. statické metody, které nemají přístup k atributům objektu, ale jsou součástí třídy , označují se dekorátorem @staticmethod

Objekt - příklad

class Zamestnanec:
    def __init__(self, jmeno: str, hodinovy_plat: float):
        self.jmeno = jmeno
        self._hodinovy_plat = hodinovy_plat
        self.uvazek = 1.0

    def plat(self) -> float:
        return self._hodinovy_plat

    def nastav_plat(self, hodinovy_plat: float) -> None:
        self._hodinovy_plat = hodinovy_plat

    def zvys_plat(self, navyseni_o: float) -> None:
        self._hodinovy_plat += navyseni_o

    def mesicni_plat(self, odpracovanych_hodin: float) -> float:
        return self._hodinovy_plat * odpracovanych_hodin

    ## statická metoda, jedná se o ukázku, ale zde by mohla být i normální metoda
    @staticmethod
    def delka_pracovniho_dne(uvazek: float = 1.0) -> float:
        return 8 * uvazek

    @property
    def hodin_denne(self) -> float:
        return self.delka_pracovniho_dne(self.uvazek)

    @property
    def denni_plat(self) -> float:
        return self._hodinovy_plat * self.hodin_denne

    def __repr__(self) -> str:
        return f"Zamestnanec {self.jmeno} s platem {self._hodinovy_plat} za hodinu"

Použití objektu

odpracovane_hodiny = 160
zam = Zamestnanec("Testovaci Zamestnanec", 250)
print(f"Denní plat: {zam.denni_plat}")
zam.uvazek = 0.5
print(f"Denní plat: {zam.denni_plat}")
print(f"Plat: {zam.mesicni_plat(odpracovane_hodiny)}")
zam.zvys_plat(50)
print(f"Plat po zvýšení: {zam.mesicni_plat(odpracovane_hodiny)}")
Denní plat: 2000.0
Denní plat: 1000.0
Plat: 40000
Plat po zvýšení: 48000

Dotazy?