přihlásit 11544/601735

Komentáře a dokumentační řetězce

Až budete psát trochu delší programy, zjistíte, že by se vám hodilo si do programu psát vlastní poznámky. Třeba co znamená tohle a k čemu slouží onohle, či připomínku, že tady ten kousek kódu je napsaný na rychlo a že je to ještě potřeba dodělat pořádně. Přesně k tomu slouží komentáře. Na konci kapitoly se dozvíte, že psát komentáře není jen možnost, ale přímo nutnost.

Python zná vcelku běžné jednořádkové komentáře, které začínají znakem # a platí až do konce řádku. Víceřádkové komentáře nezná, ale umí víceřádkové textové řetězce, které se používají jako komentáře.

Je-li takový víceřádkový řetězec/komentář umístěn na začátek funkce, metody, třídy nebo modulu, tak s ním Python nakládá jako s dokumentačním řetězcem. Jestli jste si všimli u IDE pythonwin, že poskytuje nápovědu k funkcím, tak vězte, že ji získává právě z dokumentačních řetězců. Když budete psát dokumentační řetězce u vlastních funkcí, bude vám nabízet nápovědu i u vašich vlastních funkcí.

Něco podobného nabízí i WingIDE, který dokumentační řetězce používá jako zdroj informací pro funkci Source Asistent. Můžete s na to podívat na screenshotu. Je na něm i ukázka komentářů i dokumentačního řetězce (nepřehlédněte odezvu v pravém dolním okně).

To samé umí třeba i textový editor Vim a další programy a dokonce s nimi umí pracovat i interaktivní interpret. Standardní knihovny Pythonu a nejen ty jsou poctivě ověnčeny dokumentačními řetězci, takže toho neváhejte využít. Z podstaty věci to může být ta nejaktuálnější a nebo dokonce jediná dokumentace.

Komentáře jsou základní součástí kódu a kvalitní zdrojové kódy jsou dobře okomentované. Je to především investice do budoucnosti, protože když se na svůj kód podíváte třeba po roce, tak řada věcí, které se vám při psaní programu zdála zřejmá, se vám už tak zřejmá zdát nebude. Tuplem to platí pro ostatní programátory, kteří budou číst váš kód.

Abyste dokázali ocenit správný zápis kódu, zkuste pochopit co dělá tato ukázka:

dataLck.acquire()

if  not idP in data:
   data[idP]=[timeP, timeP, 0, [0]*3600]

dataP = data[idP]

if  dataP[1] != timeP:
   dataPS   = dataP[3]
    oldTimeP = dataP[1]
    if  timeP - oldTimeP > 3600:
        oldTimeP = timeP - 3600
    for t in xrange(oldTimeP+1, timeP+1):
        dataPS[t%3600] = 0

idx = timeP % 3600

dataP[1]       = timeP
dataP[2]      += sizeP
dataP[3][idx] += sizeP

dataLck.release()

Následuje ten samý kód, který se ale drží zásad správného psaní komentářů a pojmenovávání identifikátorů (někdo by mohl mít výhrady proti tomu, že komentáře a identifikátory jsou v češtině):


dataLck.acquire()

""" UKLOZENI INFORMACE O OBJEMU PRENESENYCH DAT
Kazde tcp/ip spojeni ma svuj zaznam ve slovníku data,
indexem je id spojeni. Uklada se celkova suma prenesenych
dat na spojeni a dale se zaznamenava posledni hodina po
sekundach za pomoci kruhoveho bufferu. Indexem do kruhového 
bufferu je poradi sekundy v hodine. To znamena, ze pri 
vzniknuti spojeni o pul se buffer zacne vyplnovat od sve 
poloviny."""

if  not idSpojeni in data:
    # nove spojeni > zalozit novy zaznam
    data[idSpojeni]=[aktualniCas, # 0 - cas zahajeni spojeni
                     aktualniCas, # 1 - cas posledniho zaznamu
                     0,           # 3 - suma prenesenych dat
                     [0]*3600     # 3 - kruhovy hodinovy buffer
                     ]

dataSpojeni = data[idSpojeni] # zkraceny odkaz na data spojeni

if  dataSpojeni[1] != aktualniCas: # nova sekunda
    # provest vynulovani starych hodnot sekundovych 
    # registru mezi poslednim zadanym a aktualnim casem
    posledniCas = dataSpojeni[1]
    bufer       = dataSpojeni[3]
    if  aktualniCas - posledniCas > 3600:
        # rozdil je vetsi nez cely bufer:
        # podstrcit falesny posledni cas, aby se 
        # buffer nemazal zbytecne nekolikrat dokola
        posledniCas = aktualniCas - 3600
    for cas in xrange(posledniCas+1, aktualniCas+1):
        bufer[cas%3600] = 0 # cas%3600 = index do bufferu

idx = aktualniCas % 3600     # index na aktualni sekundu

dataSpojeni[1]       = aktualniCas   # posledni zadany cas
dataSpojeni[2]      += aktualniObjem # celkova suma
dataSpojeni[3][idx] += aktualníObjem # sekundova suma

dataLck.release()

Tento kód je poněkud delší a stálo trochu času navíc ho napsat. Odměnou je podstatně větší srozumitelnost, která se vám časem mnohonásobně vyplatí. Kdykoli později budete svůj kód číst, budete mít méně potíží jej pochopit. Tím ve výsledku čas nakonec ušetříte. Dále tím zvýšíte pravděpodobnost odhalení chyb při revizních čteních a také snížíte riziko vnesení nových chyb do programu při jeho modifikacích.

Proto, i když program ke své činnosti komentáře nepotřebuje, nejsou zbytečné. Jsou velmi důležité pro údržbu kódu. Psaní dobrých komentářů je samozřejmou součástí práce dobrých programátorů. Naučit se dobře komentovat programy není snadné, chce to praxi a trochu zkušeností s pracným louskáním zdrojáků, které jste napsali před rokem. Pak pochopíte, co je banalita a co je důležité a jak okomentovat. Časem zjistíte, že dobře napsat komentář a zvolit název identifikátoru znamená dobře chápat podstatu úlohy, kterou algoritmizujete a naopak, psaní komentáře vám pomáhá lépe pochopit podstatu této úlohy a lépe ji algoritmizovat. Takže, nebuďte líní a pište komentáře. A pamatujte, minutový komentář k novému kódu, který není napsán hned bude napsán až po té, co jste ztratíte hodinu času louskáním pár řádků toho času už starého kódu :-).


Parse error: syntax error, unexpected T_STRING in /web/htdocs2/wraithcz/home/www/python/data/sessions/sessions1.php on line 2