Úvod do programovania v Pythone (praktická časť)

Skôr, ako sa zahryzneme do analýzi a poniektorí azda aj vylepšovania niekoľkých zaujímavých a jednoduchých pluginov pre čítač obrazovky NVDA, oboznámime sa ešte s konceptom trieda, spomenutým na konci teoretickej časti. Kopec toho zanedbáme, povieme si len to, čo naozaj treba na to, aby sme mohli porozumieť vyššie spomenutým príkladom. Záujemcovia o konzistentné a vyčerpávajúce informácie nahliadnu do seriálu spomenutého v prvej časti tohoto minikurzu a do dokumentov spomenutých na konci tohoto textu.

Zľahka o triedach

V predchádzajúcom sme sa viac krát stretli s použitím objektov. Jazyk python je plne objektový jazyk, z čoho vyplýva, že všetko v jazyku je objekt.

---(číselná premenná)

>>> a=5

>>> dir(a)

['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real']

---

Funkcia dir, ktorú sme v príklade použili vypíše všetko, čo je v objekte definované. Teda všetky atribúty a metódy.

O metódach už niečo vieme, atribútmy budeme nazývať premenné, ktoré sú definované vovnútry v objekte.

Ukážme si ešte jeden objekt:

---(funkcia)

>>> def pokus():

... print "ahoj, ja som funkcia pokus"

...

>>> pokus()

ahoj, ja som funkcia pokus

>>> dir(pokus)

['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']

---

Z textu vyššie vidíme, že aj funkcia je objekt. Môžete si vyskúšať vyvolať help na ľubovoľného člena funkcie.

Na to aby mohli v pythone vznikať objekty, musia existovať tzv triedy, z ktorých sa objekty vytvárajú. Ako celkom fajn analógiu z reálneho sveta môžme použiť škatuľku. Škatuľkou nazveme hocičo, čo je vovnútri duté, dá sa to nejako otvoriť, nieje to príliš veľké no zároveň je vo vnútri dosť priestoru na to, aby sa ta dalo niečo vložiť. Pojem škatuľka teda môžme nazvať triedou.

Ak si predstavíme nejakú konkrétnu škatuľku, napríklad tú od lentiliek, tak sme jej priradili nejaké presné črty (materiál, rozmery, otvárateľnosť z oboch strán, grafický popis) a budeme jej hovoriť objekt. Objekt škatuľka od lentiliek je inštanciou triedy škatuľka.

Rovnako v pythone existuje trieda list, ktorá sa použije ako "šablóna" v prípade, že vytvárame objekt typu zoznam. (vyskúšajte dir(list)).

Skúsme si teraz vyrobiť triedu škatuľka:

---(trieda skatulka)

class skatulka:

dlzka=0

vyska=0

sirka=0

obojstranna=""

popis=""

pocet=0

def __init__(self,dlzka,sirka,vyska,obojstranna,popis):

self.dlzka=dlzka

self.sirka=sirka

self.vyska=vyska

self.obojstranna=obojstranna

self.popis=popis

skatulka.pocet+=1

def objem(self):

return self.vyska*self.sirka*self.dlzka

---

Uložte ju do priečinka python, ktorý sme si vyrobili a použite v konzole (nezabudnite si do sys.path pridať cestu k priečinku python, po reštarte nvda tam nieje).

---

>>> import a # moj modul so skatulkou sa vola a.py

>>> zoznam=[]

>>> zoznam.append(a.skatulka(5,5,5,"nie","na nausnice"))

>>> zoznam.append(a.skatulka(5,4,1,"nie","od zapaliek"))

>>> zoznam

[<a.skatulka instance at 0x05ABE8F0>, <a.skatulka instance at 0x055A51E8>]

>>> for x in zoznam:

... print "%s ma objem %f" %(x.popis,x.objem())

...

na nausnice ma objem 125.000000

od zapaliek ma objem 20.000000

>>> a.skatulka.pocet

2

---

Nakoniec ešte pár poznámok ku kódu triedy:

zľahka o dedičnosti (inheritance)

Z doteraz poznaného nám snáď vyplýva, že triedy majú pre bežného programátora veľký význam v tom, že nám umožňujú použiť existujúci kód. Ak si vytvoríme zoznam, nemusíme sa zamýšľať nad tým, akým spôsobom ho metóda sort utriedi, ako je v pamäti reprezentovaný, pretože aj tieto veci za nás rieši trieda list.

Triedy teda možno chápať ako batérie užitočných kusov kódu, ktoré môžeme používať v našich programoch. Ich celkom zaujímavou vlastnosťou je ale aj fakt, že ich môžeme rozširovať. Môžme vyrobiť svoju vlastnú triedu, ktorá je založená na inej triede. Vlastne každá trieda (aj tá ktorú sme vytvorili v predchádzajúcej kapitole) je založená na nejakej triede.

Ak vytvoríme triedu, ktorú odvodíme z inej existujúcej triedy, môžeme meniť metódy pôvodnej triedy, ale aj vytvárať nové metódy, ktoré nadradená metóda nemá.

Práve na dedičnosti a upravovaní metód je založené vytváranie pluginov pre NVDA. Skôr, ako sa pustíme do hrania sa s prvým jednoduchým nvda pluginom, priblížme si ešte dedenie a upravovanie metód na nejakom príklade z reálneho života.

V knižkách o programovaní sa dedenie často prirovnáva k ríši zvierat. My ale tento problém skúsime uchopiť cez ovládanie rádia, pretože to sa bude aspoň trochu podobať na to, čo robí nvda s global pluginmi.

Ak si predstavíme bežné rádio a jeho ovládanie, tak má určite vypínač, ktorým ho môžeme zapnúť, ďalej nejaké ladiace prvky, ovládač hlasitosti a povedzme že ešte prepínanie vĺn. Ak vieme akým spôsobom sa tieto ovládacie prvky označujú, tak by pre nás nemalo byť ťažké ovládať ľubovoľné rádio.

Existujú rôzne rádiá, ktoré k bežnému štandardu pridávajú rôzne funkcie navyše a okrem toho fungujúna rôznych princípoch. Povedzme že úplne základné rádio má riešené ladenie staníc otočným kolieskom.

Potom môže existovať iné rádio, ktoré má rovnaké vlastnosti ako to základné (dá sa zapnúť, dať tichšie a hlasnejšie,...) len ladenie staníc je riešené digitálnym spôsobom. Ak výrobca rádia vyrobil ladenie tak, že z rádia trčí otočné koliesko, ktorého točením ladíme stanice, tak nás vôbec netrápi, ako samotné ladenie staníc funguje, hoci by bolo vo vnútri otočné koliesko aj sprevodované na nejaký digitálny ladiaci systém. Z nášho pohľadu toto moderné rádio zdedilo všetky vlastnosti toho základného.

Tretie rádio môže pridávať napríklad možnosť ukladať predvoľby do pamätí. Ak by sme o takejto funkcii nevedeli, tak by sme mohli pokojne tlačidlá slúžiace na ukladanie staníc ignorovať a rádio používať ako klasické. Toto rádio však pridáva nejaké nové funkcie, teda rozširuje obyčajné základné rádio.

Čítač obrazovky nvda obsahuje špeciálnu triedu nazvanú globalPluginHandler.GlobalPlugin, ktorá definuje nejaké základné metódy a atribúty, cez ktoré nvda dokáže komunikovať so všetkým čo je na tejto triede založené. Teda, táto trieda je to základné rádio, ktoré NVDA vie ovládať, pretože definuje, na čo presne sa mápoužiť ktorý atribút a kedy sa zavolá ktorá metóda.

My môžme vytvárať triedy odvodené z tejto základnej triedy a upraviť metódy a atribúty tak, aby na to čítač obrazovky NVDA "neprišiel" (z jeho pohľadu obsahujú atribúty zmysluplné hodnoty a metódy vracajú to, čo sa očakáva). Okrem toho môžeme tieto triedy rozširovať o nové funkcie, o ktorých nvda nemusí vedieť, pretože to sú metódy, ktoré sú určené na rôzne pomocné úlohy a volajú sa z metód, ktoré volá nvda.

Pozrime si teraz úplne jednoduchý plugin, ktorý pridá do sys.path cestu k priečinku python, na disku c.

---(mojpython.py)

import globalPluginHandler

import sys

class GlobalPlugin(globalPluginHandler.GlobalPlugin):

def __init__(self):

super(GlobalPlugin, self).__init__()

sys.path.append("c:\\python")

---

Pozrite si aj help k triede Global Plugin, aby ste mali základný prehľad.

Posledná informácia, ktorá vám ešte môže naozaj chýbať je fakt, že akékoľvek nezrovnalosti v kóde, nad ktorými na konzole interpreter hundral rovno do výstupného poľa konzoly sú v prípade nvda pluginov komentované v nvda logu (nástroje/zobraziť log).

Hra šnaps

Stiahnite si funkčnú implementáciu. Pravidlá hry snáď poznáte, tuhľa stručné zhrnutie:

Ovládanie hry

Chyby

Hra obsahuje niekoľko úmyselne urobených a možno aj nejaké neúmyselné chyby. Tu je krátky zoznam, aj s poznámkami, skúste ich opraviť:

farby

Tú ste určite neprehliadli. Každá karta má všetky 4 farby. Nejaký nápad? Ak by náhodou nie, tak si vyskúšajte v konzole tento kúsok kódu:

---(he he he)

>>> zoznam1=[1,"ahoj"]

>>> zoznam2=zoznam1

>>> zoznam2[1]+=" jozo"

>>> zoznam1

[1, 'ahoj jozo']

---

To je ale zákerné čo?

Triedenie kariet

Možno ste si všimli, že triedenie nefunguje celkom tak ako by malo. Vyskúšajte si pozrieť vaše karty hneď po rozdaní. Opravte aj triedenie kariet počítača, je v ňom rovnaká chyba.

vylepšenia

Ak si trúfate, tak môžete skúsiť nasledovné: