Tutorial programování v Pythonu

Python se čím dál tím víc začíná šířit mezi programátory a tvůrci webových stránek. Preferují ho zejména mladí programátoři, kteří si rádi vyzkouší něco nového a nespokojí se s rutinou jazyka C, který zatím používá většina programátorů. Tímhle článkem bych chtěl přiblížit programovací jazyk Python všem čtenářům tohohle blogu. Jedno z nejlepších vývojářských prostředí v linuxu je program Pycharm. Začneme tudíž instalací samotného Pycharmu. Postup je podrobně popsán na téhle stránce http://sumnous.wordpress.com/2012/10/17/install-pycharm-and-jdk-on-ubuntu-12-04/ , takže tady nebudu uvádět podrobnosti. Základní příkazy pro Python

Příkaz Co dělá? Příklad
Přiřazení Vytváření reference jana = ‚ta‘
Volání Spouští funkce stdout.write(„spam,ham \n“)
print Vypisuje objetky print ‚Vtip:‘, vtip
if/elif/else Volí z variant dalšího běhu if „python“ in text: print text
for/else Prochází posloupností for x in mylist: print x
while/else Cyklus while while 1: print ‚hello‘
pass Prázdný příkaz while 1: pass
break, continue Skoky v rámci cyklu while 1: if not line: break
try/except/finally Zachycuje vyjímku try: action() / except: print ‚action error‘
raise Vyvolá vyjímky raise endSearch, location
import, from Řídí přístup k jménům modulů import sys; from sys import stdin
def Definuje funkci def f(a, b, c=1, *d) return a+b+c+d[0]
class Vytváří nové typy objektů class subclass: StaticData = []
global Jmenné prostory def function(): global x, y; x = ‚new‘
del Maže věci del data[k]
exec Spouští kod exec „import “ – modName in g, 1
assert Kontroly assert X > Y

Základní datové typy

  1. Číselné typy
    • int – integers, čísla celá
    • long – long integers, čísla celá neomezené délky (jen v Pythonu 2.x)
    • float – čísla s desetinnou tečkou
    • complex – komplexní čísla
    • bool – typ s hodnotami True a False
    • NoneType – specielní typ s jedinou hodnotou None
  2. Sekvence
    • str – string, řetězec znaků
    • unicode – řetězec, předznačený literálem ‚u‘ (jen v Pythonu 2.x)
    • byte – pořadí celých čísel od nuly do 255
    • list – seznam
    • tuple – entice
  3. Sety
    • set – neuspořádaná kolekce jedinečných objektů
    • frozen set – totéž jako set ale neměnitelné (immutable)
  4. Mappings
    • dict – dictionary neboli slovník – neuspořádaná kolekce párových objektů key: value

Teď si vysvětlíme jeden z nejjednodušších příkladu právě Pythonu s grafickým rozhraním GTK.

#!/usr/bin/env python

import gtk

okno = gtk.Window()
tlacitko = gtk.Button("Ahoj")

okno.add(tlacitko)
tlacitko.connect("clicked", gtk.main_quit)

okno.show_all()

gtk.main()
Ahoj Linux

Výsledek v Linuxu… Rozbor kodu import gtk  Naimportuje GTK a díky tomu pak můžeme používat objekty z této knihovny stylem náš_objekt = gtk.objekt okno = gtk.Window()  Veškeré prvky jsou instance tříd. Tudíž si takto vytvoříme objekt okno, který je instancí třídy gtk.Window. To bylo odborné vysvětlení. Neodborné je, že máme objekt okno, které je gtk.Window() a má všechny jeho vlastnosti, které můžeme číst a upravovat. tlacitko = gtk.Button("Ahoj")  To samé jako ve vyšším případě, akorát vytváříme tlačítko a rovnou mu jako parametr předáváme chtěný nápis, jinak bychom museli na dalším řádku mít tlacitko.set_label("Ahoj"). okno.add(tlacitko)  To, že máme tlačítko, neznamená, že víme, kde bude. Teď už ano, bude v: okno. tlacitko.connect("clicked", gtk.main_quit)  A tedy nám, konečně, začíná přituhovat. Jak GTK, tak Qt pro jednotlivé widgety (objekty oněch toolkitů, okno je widget, tlačítko je widget, posuvník je widget apod.) eviduje signály, které tento widget může vyslat. Tlačítko gtk.Button(), dle referenční příručky, umí vyslat, odborně emitovat, signály activateclickedenter,leavepressed a released. My využíváme „clicked“ (název signálu je řetězec, proto uvozovky) a po vyvolání tohoto signálu vyvoláváme funkci gtk.main_quit, která ukončí naší GTK aplikaci. Závorky nejsou, protože napojit se lze pouze na funkce nebo metody. Pokud chceme oné funkci předat parametry, zapisují se jako další parametry. Např. sčítací funkce – klasicky volaná secti(12,23)  – bude v connectu volána:něco.connect("clicked", secti, 12, 23). okno.show_all()  To, že prvky vytvoříme, neznamená, že jsou zobrazeny. Nejdříve jim měníme vlastnosti nebo chceme, aby se zobrazily až při nějaké události. To se stane, až když zavoláme jejich metodu show(). Zde používám objekt.show_a­ll(), což zobrazí i přiřazené prvky, tzv. child objekty, tudíž i tlačítko, jinak bych jej musel zobrazit sám pomocí tlacitko.show(). gtk.main()  Začátek „smyčky“. Všechny výše napsané řádky jsou procedurálního (krok za krokem) charakteru. Aneb dojde se k nim, provedou se a tím to hasne. Schválně si zkuste tento řádek vykomentovat (#). Zjistíte, že Python tento kód bez řečí/chyb provede, jen se nic nestane. On ty prvky vytvoří i je předá k zobrazení, pak ale interpreter skončí a uklidí za sebou → zase je hezky vymaže. gtk.main() je právě ten řádek, na kterém se interpreter zastaví a předá řízení GTK. Pokud za gtk.main() vložíte třeba print "Jsem za GTK", zjistíte, že v konzoli se tento nápis neobjeví dříve, než se stiskne tlačítko, které vyvolá gtk.main_quit() – ano, právě tento příkaz ukončí GTK smyčku. Interpreter se tak konečně dostane k našemu print, do konzole se napíše „Jsem za GTK“ a program skončí. Skriptování ve více vláknech Vlákna jsou užitečná proto, že dnes už téměř každý procesor pro počítač nebo notebook mají 2 a více jader. Za pár let budou základní procesory s mnohem větším počtem jader. Multithreading je důležitý hlavně proto, že na každé stránce je mnoho flashových aplikací, v pozadí běží hudba a ktomu potřebujeme ještě pracovat. Proto potřebujeme procesor, který dokáže vykonávat několik úloh najednou. V Pythonu najdeme vlákna v několika implementacích. Řekneme si o dvou z nich. Jedna je podobná vláknům v javě, kdy je každé z nich samostatný objekt odvozený od třídy Thread. Druhou možností je funkce start_new_thread(). Pomocí ní můžeme kteroukoli funkce spustit jako vlákno. Komunikace mezi vlákny se nazývá synchronizace. V Pythonu nám pomohou objekty Event, RLock, Lock nebo Semaphore. Zámky Tato stručná teorie by nám měla stačit. Možná se teď ptáte, co se děje při přístupu ke sdílené pamětí, pokud se dvě vlákna rozhodnou zapsat na stejné místo paměti. Když se tak stane, hodnota která vznikne je s velkou pravděpodobností nepoužitelná. Konkrétně na tuto situaci se používá tzv. Mutex. Jedná se o zámek, který zamkne nějakou část kódu zatímco ji vykonává jedno vlákno a ostatní čekají. Této části kódu se říká kritická sekce. V C je to třeba implementované tak, že se na začátek kritické sekce nasadí funkce s ukazatelem na Mutex. Pokud je již nějaké vlákno v kritické sekci, tak vlákno čeká na uvolnění právě na této funkci. V Pythonu to je hodně podobné, pouze jsou zde Mutexy implementované jako objekty Lock a RLock. Lock a RLock jsou více méně totožné, pouze ten druhý můžeme bezpečně použít několikrát. Události Může se stát, že nám běží deset různých vláken vykonávajících nějakou úlohu. První pět má připravit data k použití a dalších pět ty data použije. Normálně bychom mohli nastartovat prvních pět, počkat až skončí, pak dalších pět. Došlo by však ke zbytečně prodlevě. I těch druhých pět vláken se musí připravit a musí vůbec vzniknout. Mnohem lepší způsob je nějaká možnost synchronizace práce mezi jednotlivými vlákny. V Pythonu k tomu máme objekt Event, ten si vytvoříme a pak předáme všem vláknům. Jedno vlákno z první pětice ho po vykonání nastaví na True a další vlákno, tentokrát z druhé pětice, na tuto událost čeká. Provádění tak může začít ihned po nastavení True. Druhá zmíněná možnost je nastartování vláken z druhé pětice po vykonání všech z první pětice. To můžeme udělat pomocí metody join(), která se chová podobně jako Event, ale je to metoda samotného objektu vlákna. Funkce Start_new_thread() Začneme tou nejjednodušší ze zmíněných možností, start_new_thread(). Tato funkce spustí jinou funkci ve vlákně. Komunikace mezi procesem a vláknem je dost omezená:

<code>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
from thread import start_new_thread

def go(p1,p2):
    print "Já jsem thread"
    print "\t Parm. 1:",p1,"Parm. 2:",p2

start_new_thread(go,("p11","p12"))
start_new_thread(go,("p21","p22"))

time.sleep(1)</code>

Když nepočkáme na ukončení běhu obou vláken, dostaneme s velkou pravděpodobností výjimku. Modul threading Mnohem užitečnější je modul threading. Zvenku je podobný vláknům z Javy. Začneme tím, že si ukážeme jak vytvořit a spustit vlákno:

<code>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys,os,time
from threading import Thread

class ct(Thread):
    def __init__(self,name,i):
        Thread.__init__(self)

        self.i = i
        self.name = name

    def run(self):
        for x in range(5):
            print self.name+":",self.i-x
            time.sleep(0.1)

t1 = ct("t1",5)
t2 = ct("t2",5)
t3 = ct("t3",5)
t1.start()
t2.start()
t3.start()</code>

Na výstupu se objeví zprávy ze všech tří vláken. Pořadí zpráv bude náhodné. Lock(Rlock)

<code>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys,os,time
from threading import Thread,RLock

class ct(Thread):
    def __init__(self,name,i,l):
        Thread.__init__(self)

        self.i = i
        self.l = l
        self.name = name

    def run(self):
        self.l.acquire()
        for x in range(5):
            print self.name+":",self.i-x
            time.sleep(0.1)
        self.l.release()

l = RLock(False)

t1 = ct("t1",5,l)
t2 = ct("t2",5,l)
t3 = ct("t3",5,l)
t1.start()
t2.start()
t3.start()</code>

Díky zámku v tomto příkladu dostaneme zprávy postupně ze všech tří vláken. Nebudou se míchat jako v předchozím příkladě. Druhá možnost je použít metody Thread.join() v kořenovém procesu. Kód by mohl vypadat třeba takhle:

<code>[...]
t1.start()
t2.join()
t2.start()
t2.join()
t3.start()
[...]</code>

Event

<code>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys,os,time
from threading import Thread,Event

class ct1(Thread):
    def __init__(self,name,i,e):
        Thread.__init__(self)

        self.i = i
        self.e = e
        self.name = name

    def run(self):
        print "Čekám na signál"
        e.wait()
        for x in range(3):
            print self.name+":",self.i-x
            time.sleep(0.1)

class ct2(Thread):
    def __init__(self,e):
        Thread.__init__(self)

        self.e = e

    def run(self):
        print "Čekáme"
        time.sleep(1)
        print "Odemknutí"
        self.e.set()

e = Event()

t1 = ct1("t1",3,e)
t2 = ct2(e)
t1.start()
t2.start()</code>

Poslední ukázka používá Event k předání signálu z jednoho vlákna do druhého. Nejdříve nastartujeme obě vlákna. Druhé vlákno se dostane k metodě wait() a čeká. První vlákno chvilku spí a po probuzení pošle zprávu pomocí set(). Hned poté začne druhé vlákno vykonávat svoji práci.   Video pro používání Glade Glade je grafické uživatelské rozhraní pro tvorbu aplikací GTK+. V tomto videu se pokusím Vám přiblížit základní pracovní úkony v tomhle programu. Program můžeme v Linuxu naistalovat klasickým příkazem

<code>apt-get install glade</code>

Poté spustíme Glade a můžeme začít tvořit první aplikaci. Glade má mnoho ovládacích prvků, kterými může přidávat okna, tlačítka atd. Po vytvoření vzhledu stránky podle našich představ, uložíme soubor s příponou .glade a můžeme začít programovat v Pythonu. Úkážu vám jeden z jednošších příkladů programování v Pythonu a Gladu.