Python kezdőknek kurzus 8. lecke

A Ubuwiki wikiből

Extrák

Eredeti lecke: http://www.shallowsky.com/python/lesson8.txt


Ebben a leckében pár hasznos dologról lesz szó, melyek a korábbi leckékbe nem fértek bele. Lesz még egy lecke további extrákról, beleértve grafikus keretrendszereket és számos más trükköt.

Kivételek kezelése

Természetesen mindig úgy próbálunk kódot írni, hogy ne legyenek benne hibák. De néha ennek ellenére történnek hibák, és a programunknak ezekkel kezdenie kell valamit.

A Python rendelkezik eszközökkel, melyek kezelik a hibákat, illetve az ún. kivételeket.

Íme egy példa:

Python 2.x Python 3.x
try :
    fajlnev = "/nincs/ilyen/fajl"
    fajlom = open(fajlnev)
    for sor in fajlom :
        print sor
except IOError, err :
    print "Nem lehetett megnyitni:", fajlnev
    print "A hiba:", err
print "Program vege, ha tortent hiba, ha nem."
try :
   fajlnev = "/nincs/ilyen/fajl"
   fajlom = open(fajlnev)
   for sor in fajlom :
       print(sor)
except IOError as err :
   print("Nem lehetett megnyitni:", fajlnev)
   print("A hiba:", err)
print("Program vege, ha tortent hiba, ha nem.")

try jelentése: itt egy kódblokk, melyben történhet hiba. Próbáljuk futtatni és ha valami hiba történik, keressünk egyezést az ‘except’ résszel és tegyük azt, ami ott szerepel.

Ezek után van egy except kulcsszó, amit a hiba típusa (itt az IOError) követ, majd a változó neve, amibe a Python a hibára vonatkozó információkat írja.

Nézzük meg mi történik, ha kihagyjuk a try/except részt:

>>> fajlnev = "/nincs/ilyen/fajl"
>>> fajlom=open(fajlnev)
Traceback (most recent call last):
  File "<stdin>", sor 1, in <module>
IOError: [Errno 2] No such file or directory: '/nincs/ilyen/fajl'

A fentiekből látszik, hogyha egy fájl nem létezik, akkor IOError típusú hibát kapunk. Ha más hibaüzenetet kapunk, akkor valószínűleg annak nem a fájl megnyitásához van köze.

Előfordulhat, hogy MINDEN típusú hibát le szeretnénk kezelni. Nem szükséges megadni (konkrétan a) kivételek típusát, vagy változót, használhatjuk az except-et például így is:

except :
    print "Valamilyen hiba történt"

Az is lehet, hogy szeretnénk minden típusú hibát kezelni, viszont szükségünk van változóra is, ami segíti annak eldöntését, hogy milyen hibával van dolgunk. Ilyen esetben használhatjuk az alábbi formát:

except Exception, hiba :
    print "Valamilyen hiba történt:", hiba

Ugyanazon try segítségével többféle típusú hibát is kezelhetünk:

Python 2.x Python 3.x
try :
    fajlom = open(fajlnev)
    for sor in fajlom :
        i = 12 / 0
        print sor
except IOError, hiba :
    print "Nem lehetett megnyitni", fajlnev
    print "A hiba:", hiba
except Exception, hiba :
    print "A hiba (nem IOError):", hiba
try :
   fajlom = open(fajlnev)
   for sor in fajlom :
       i = 12 / 0
       print(sor)
except IOError as hiba :
   print("Nem lehetett megnyitni", fajlnev)
   print("A hiba:", hiba)
except Exception as hiba :
   print("A hiba (nem IOError):", hiba)

Természetesen az Exception osztály, illetve alosztályai rengeteg részletes információt tartalmaznak a hibákról. További részletek a http://docs.python.org/tutorial/errors.html oldalon.


Opcionális paraméterek

Írhatunk olyan függvényeket, melyeknek bizonyos paraméterei opcionálisak (választhatóak).

Például:

Python 2.x Python 3.x
def udvozlet(vezeteknev, keresztnev, nyelv="python", oprendszer=None) :
    print "Udv", vezeteknev, keresztnev
    print "Latom", nyelv, "nyelven programozol. "
    if oprendszer :
        print "es", oprendszer, "rendszert hasznalsz "
def udvozlet(vezeteknev, keresztnev, nyelv="python", oprendszer=None) :
   print("Udv", vezeteknev, keresztnev)
   print ("Latom", nyelv,"nyelven programozol.")
   if oprendszer :
       print("es", oprendszer,"rendszert hasznalsz")

… és számos módon meghívhatod:

udvozlet("Linus", "Torvalds")
udvozlet("Linus", "Torvalds", "c", "Linux")
udvozlet("Linus", "Torvalds", nyelv="c", oprendszer="Linux")
udvozlet("Linus", "Torvalds", oprendszer="Linux")

Minden paramétert, ahol nincs egyenlőségjel (=), szükséges megadnunk - különben hibát kapunk. Viszont ha adott egy alapértelmezett érték az = segítségével, akkor az a paraméter opcionálissá válik és nem kötelező megadni, mikor meghívjuk. Emellett a paramétereket megadhatjuk sorrendre való tekintet nélkül, ha - a fenti módon - használjuk a paraméterek neveit.

Rendszerparancsok futtatása

A Python remekül helyettesítheti a shell szkripteket - de csak akkor, ha tetszőleges rendszerparancsot tudunk meghívni. Ha Google-ben próbálnánk erre rákeresni, elég zavaros leírásokat találhatunk erről és egy részük már nem is támogatott.

Nézzük én mit is használok:

Elsőként ha egy egyszerű programot szeretnénk futtatni, abban nincs semmi nehézség:

import os
os.system("motd")
os.system("ls -l " + os.getenv("HOME”))

Ha szükségünk van a parancs kimenetére, az kicsit nehezebb. Használjuk a popen-t:

Python 2.x Python 3.x
import os
fp = os.popen('find . -name "*.jpg"')
for sor in fp:
    print sor.strip()
import os
fp = os.popen('find . -name "*.jpg"')
for sor in fp:
   print(sor.strip())

Ha szeretnénk egy parancsot paraméterekkel meghívni, az már trükkösebb. Természetesen felépíthetjük a parancssort úgy is, hogy begépeljük, például így (ahol iface értéke ‘eth0’)

os.system("ifconfig " + iface + " up")

vagy (ez jobb):

os.system("ifconfig %s up" % iface)

Nehezebb, de jobb megoldás

Az a gond az os.system és os.popen parancsokkal, hogy a teljes parancsot felépítjük és ezt adjuk az alshell-nek. Ez elég kockázatos lehet, attól függően honnan kapjuk a paramétereket. Az előző hálózati interface-es példánál tegyük fel, hogy egy felhasználótól kérjük be az iface változó értékét, aki ahelyett hogy “eth0” adna meg, az "`rm -rf /`"-et adja. A program ezt közvetlenül átadja az os.system vagy os.popen függvényeknek, mely futtatja, ami a backquote (`) jelek közt szerepel, és elvesztjük az összes fájlunkat. Ezt ugye nem akarjuk...

Így hát minden nem-triviális program esetén a subprocess modult használom. Egy program futtatása (például os.system esetén) nagyon egyszerű, listaként adjuk át.

import subprocess
subprocess.call(["ifconfig", iface, "up"])

A kimenet megszerzése egy kicsit nehezebb, mert számos különböző szintaxis létezi. A legegyszerűbb talán az alábbi:

Python 2.x Python 3.x
p = subprocess.Popen(["find", ".", "-name", "*.jpg"],stdout=subprocess.PIPE)
for sor in p.stdout :
    print sor
p = subprocess.Popen(["find", ".", "-name", "*.jpg"],stdout=subprocess.PIPE)
for sor in p.stdout :
    print(sor)

Részletes leírás a subprocessekről a http://docs.python.org/library/subprocess.html#subprocess-replacements oldalon található.

Gyakorló feladatok

Az utóbbi leckék alapján érdemes esetleg újraírni a korábbi gyakorló feladatainkat. Használhatunk például függvényeket, opcionális paraméterekkel.

Akiknek esetleg több idejük van gyakorolni megpróbálhatják a következőt: írjanak python szkriptet olyasmire, amit amúgy shell szkripttel oldanának meg (például szeretnénk megtalálni egy fájlt a fájlrendszerben, vagy grep-pel szűrnénk egy fájlban). Használjunk kivételkezelést és függvényeket!

Például én a fényképeimet dátum szerinti könyvtárakba szoktam rendezni és minden könyvtárban van egy fájl, Kulcsszo névvel. Van egy python szkriptem, ami keres a fotóim közt és megtalálja az összeset, amiben lepkék vagy autók vannak.


Van egy másik programom, ami végignézi melyik program (szkriptfájl) milyen nyelven íródott, és csak azok között szűr. Ez például akkor hasznos ha mondjuk a Popenről írok épp egy leckét. Ilyenkor csak kiadom a langgrep pyhton Popen parancsot és máris látom az összes python programomat, amiben a Popent használtam.

Másik hasznos program az, ami az aktuális könyvtár összes JPG képfájlát átkonvertálja vagy lekicsinyíti bélyegkép méretűre, majd egy galériát készít az összes képhez, amit weboldalunkon használhatunk.

...de ezek csak ötletek. Engedjük szabadjára a képzeletünket és találjunk valami olyasmit, ami hasznos lehet, majd programozzuk le!

További leckék

Személyes eszközök