Python / 6. časť

0

Súbory

V čase, keď pracujeme so spusteným programom (runtime), sú všetky naše údaje uložené v pamäti počítača (RAM), ktorej obsah je po ukončení vykonávania programu, resp. pri vypnutí počítača, zmazaný. Ak chceme spracúvané údaje uchovať na budúce využite, musíme ich uložiť do súborov (files). O správu súborov sa stará súborový podsystém operačného systému. Ten súbory organizuje v adresárovej (directory) štruktúre, pričom na adresovanie konkrétnej zložky alebo súboru používa cesty (paths).

Objekt, s ktorým pracujeme pri manipulácii so súbormi, nazývame tzv. držadlom (handle). Pri vytváraní handle určujeme, či chceme súbor otvoriť na čítanie ‘r‘, zápis ‘w‘ alebo doplnenie ‘a‘. Obsah súboru môžeme čítať/zapisovať buď riadok po riadku, alebo ako jeden celok. Otvorenie neexistujúceho súboru na čítanie vedie k chybe. Pri zápise do súboru, ktorý neexistuje, sa vytvorí nový súbor. Existujúci súbor sa prepíše (na zápis musíme mať, samozrejme, príslušné práva).

# Zápis písmen A B C do súboru test.txt (mfile je handle)

with open("test.txt","w") as mfile:

    mfile.write("A\n")

    mfile.write("B\n")

    mfile.write("C\n")

# Čítanie obsahu súboru test.txt riadok po riadku

with open("test.txt","r") as mfile:

    for riadok in mfile:

        print(riadok,end = "")

Optimalizácia kódu

Pri programovaní v jazyku Python sa odporúča kód optimalizovať nasledujúcimi spôsobmi:

- nepoužívame príliš dlhé riadky,

- definície funkcií uvádzame na začiatku modulov pod časť import, na oddelenie definícií používame prázdne riadky,

- názvy funkcií píšeme malými písmenami s podčiarkovníkom, v tele funkcií uvádzame dokumentačné reťazce,

- používame tzv. čisté funkcie (pure functions) namiesto modifikátorov – modifikátory menia obsah odovzdaných argumentov, čím vzniká nežiaduci bočný efekt (side effect),

- využívame priamy výpis výsledku Boolean výrazov, resp. tieto výrazy vraciame priamo výrazom return,

- používame nekonečné cykly,

- nepoužívame výraz ‘== True‘,

- ak nepotrebujeme uchovávať údaje, neuchovávajme ich.

Množiny a pevné množiny

Jedna z podstatných charakteristík typov tuple a list je taká, že položky ich záznamov sú zoradené, teda na ich výber môžeme použiť indexovací operátor. Ďalšia dôležitá vlastnosť typu tuple je nemeniteľnosť jeho položiek. Naopak, položky typu list meniť možno. Uvedené charakteristiky môžeme zhrnúť v jednoduchej tabuľke:

 

položky zoradené = indexovateľné

nemeniteľné

tuple

meniteľné

list

Jediný nezoradený typ s meniteľnými položkami, ktorému sme sa doposiaľ venovali, je typ dict. Ten však nie je sekvenčným typom, ale mapovacím. Jeho obsahom teda nie je zoznam položiek, ale zoznam párov. Python preto zavádza ďalšie dva dátové typy, ktoré dopĺňajú uvedené typy o množiny s nezoradenými položkami:

 

položky zoradené

položky nezoradené = neindexovateľné

nemeniteľné

tuple

frozenset

meniteľné

list

set

Množiny (sets) a pevné množiny (frozensets) disponujú vlastnosťami a umožňujú vykonávať operácie podobné slovníkom. Definícia množiny/pevnej množiny má nasledujúci tvar:

mnozina = set([“a“,“b“,“c“,…])

mnozina = frozenset([“a“,“b“,“c“,...])

Na prácu s množinami môžeme využívať napr. nasledujúce metódy:

add()

Pridanie položky do množiny, ak ešte v množine neexistuje

union(), |

Spojenie množín

intersect(), &

Prienik množín = položky, ktoré sú v množinách rovnaké

difference(), -

Položky, ktoré sú v množinách rozdielne

clear()

Vymazanie obsahu množiny

Rekurzia

Jedna z najbežnejších funkcionalít, ktorá je implementovaná v mnohých programovacích jazykoch, je tzv. rekurzia. Ide o programovú konštrukciu, v rámci ktorej funkcia volá samu seba. Väčšina rekurzií sa dá riešiť aplikáciou cyklu for, no v prípadoch, pre ktoré je rekurzia príznačná, je vhodnejšie použiť práve túto konštrukciu. Na správne fungovanie musí rekurzia v určitom kroku dospieť k bodu ukončenia (návratu). V opačnom prípade dôjde k nekonečnému zacykleniu a skôr či neskôr k prekročeniu pamäťového limitu (maximum recursion depth).

K najznámejším aplikáciám rekurzie určite patria tzv. fraktály. Tie sú najčastejšie zobrazované v podobe grafických obrazcov, pričom komplexný celok (high-level) sa skladá z teoreticky nekonečného množstva rovnako vyzerajúcich menších celkov (low-level). Príklad fraktálu stromu možno vidieť na obrázku. V tele funkcie draw_fracttree() možno nájsť dve jej vlastné volania. Prvé z nich (posun doľava) sa vykoná určený počet krát, pričom po dosiahnutí (vykonaní) posledného kroku program pokračuje na druhom volaní (posun doprava). Takto sa postupuje smerom vpred a vzad, až pokiaľ nebudú vykonané všetky kroky rekurzie v smere doľava aj doprava.

Aplikáciu rekurzie možno vidieť na príklade č. 8, pomocou ktorého riešime kreslenie fraktálového stromu:

import matplotlib.pyplot as plt

import math

fig,ax = plt.subplots()

ax.set(xlim = [0,600],ylim = [0,550],

       title = "Fraktálový strom")

# Rekurzívne kreslenie stromu

def draw_fracttree(x1,y1,uhol,krok):

    # Podmienka ukončenia rekurzie

    if krok:

        x2 = x1+int(math.cos(math.radians(uhol))*krok*8.0)

        y2 = y1+int(math.sin(math.radians(uhol))*krok*10.0)

        # Čiara z bodu x1,y1 do bodu x2,y2

        ax.plot([x1,x2],[y1,y2])

        # Rekurzívne volanie tej istej funkcie

        draw_fracttree(x2,y2,uhol-20,krok-1)

        draw_fracttree(x2,y2,uhol+20,krok-1)

# Prvotné volanie rekurzívnej funkcie

# - štart kreslenia stromu v bode 300,0

# - uhol natočenia čiary v 1. kroku 90 stupňov

# - počet krokov rekurzie 10

draw_fracttree(300,0,90,10)

plt.show()

V prípade rekurzívnych funkcií môžeme využiť možnosť vzájomného rekurzívneho volania (mutual recursion) viacerých funkcií, pri ktorom funkcia A volá funkciu B a funkcia B volá funkciu A. V tomto prípade je kriticky dôležité správne nastaviť bod ukončenia rekuzie tak, aby nedošlo k nekonečnému zacykleniu.

Rekurzívne typy

Už viackrát sme uviedli, že viaceré dátové typy môžu byť vnorené, teda môžu obsahovať položky, ktoré sú rovnakého typu, ako je typ, v ktorom sa nachádzajú. Ak má typ v rámci svojej definície použité položky vlastného typu, hovoríme o tzv. rekurzívnej definícii alebo rekurzívnej dátovej štruktúre. V prípade dátových typov však na rozdiel od klasickej rekurzie nejde o cyklickú rekurziu, ale o rekurziu, ktorá sa po pár krokoch končí. Na príklade možno vidieť definíciu typu list, ktorého v poradí štvrtá položka je takisto typom list. Navyše štvrtá položka tejto vnorenej položky je takisto typom list. Z uvedeného dôvodu nemožno položky premennej cisla zosumarizovať jednoduchým použitím indexu. Aj v tomto prípade si môžeme pomôcť jednoduchou rekurzívnou funkciou, ktorá diferencuje položky záznamu na položky typu int a položky typu list.

Príklad č. 9 demonštruje použitie rekurzívneho typu list:

# Rekurzívny záznam typu list

cisla = ([1,2,3,[1,2,3,[1,2,3],4,5,6],4,5,6])

# Súčet čísel v zázname - rekurzívna funkcia

def recursive_sum(zaznam):

    total = 0

    if len(zaznam) == 0:

        return 0

    for polozka in zaznam:

        if type(polozka) is list:

            total += recursive_sum(polozka)

        else:

            total += polozka

    return total

print("Záznam typu list:",cisla)

print("Súčet čísiel v zázname je:",recursive_sum(cisla))

Zobrazit Galériu

Marek Sopko

Všetky autorove články

Pridať komentár

Mohlo by vás zaujímať

Mohlo by vás zaujímať