Keresés tartalomra
Kategóriák
Címkék
- Java
- Spring
- Python
- IoC
- Android
- DI
- Dagger
- Thymeleaf
- Markdown
- JDK11
- AOP
- Aspect
- Captcha
- I18n
- JavaSpark
- Microframework
- Testing
- JUnit
- Security
- JWT
- REST
- Database
- JPA
- Gépház
- WebFlux
- ReactiveProgramming
- Microservices
- Continuous Integration
- CircleCI
- Deployment Pipeline
- Docker
- Mocking
- LogProcessing
- PlantUML
- UML
- Modellezés
- OAuth2
- Node.js
- DevOps
- Websocket
Mélyebben a Python eszközeiről
Folytatnám a Python nyelvről szóló cikksorozatom további 7 elengedhetetlenül fontos vagy legalábbis nagyon hasznos beépített lehetőségével.
Modulok
Az előző két cikk példaprogramjaiban láthattuk a forrás elején az import kulcsszót. Ezen kulcsszó segítségével importálhatunk scriptjeinkbe korábban már megírt függvénygyűjteményeket, szóval funkciója hasonló, mint a C-ben az #include, C#-ban a using vagy a Java-ban az import kulcsszavaknak. Az interpreter csatoláskor feltételezi, hogy az importált fájl .py kiterjesztésű, így ezt nem kell, sőt nem is szabad utána írnunk, csak a fájl kiterjesztés nélküli nevét kell az import kulcsszó után megadnunk (később látni fogjuk, miért). Érdekessége a nyelvnek, hogy az importált fájlokból az interpreter készít egy „lefordított” Python script fájlt, ennek kiterjesztése .pyc. Ez akkor lehet hasznos, ha egy zárt forrású programot szeretnénk publikálni, mivel így a scriptből egy .exe fájlhoz hasonló bináris fájl készül. Tudni kell viszont, hogy a script futása így nem lesz gyorsabb, csupán a modul importálása lesz fürgébb. Amennyiben módosítani szeretnénk a modult, csak az eredeti forrást kell módosítani, az interpreter ellenőrzi az időbélyegzőt, így automatikusan újrafordítja a modult, amennyiben módosulást vesz észre.
Na de nézzük, hogyan tudjuk használni a modult:
import <modulnév>
Importálás után a szimbólumkészletbe kerül a modul neve, ezután tudjuk használni a benne található függvényeket és osztályokat. Fontos megjegyezni, hogy azok neve önállóan nem kerül a szimbólumkészletbe, így minősítéssel érhetjük őket el. A minősítő operátor a pont.
<modulnév>.<tagnév>
Amennyiben a modul neve nagyon hosszú vagy kényelmetlen a használata, adhatunk neki egy aliast az as
kulcsszóval. Van még egy olyan lehetőségünk, hogy ha nincs szükségünk a teljes modulra, csak abból néhány tagra, akkor a from <modulnév> import <tagnév>
formájú utasítással csak az adott tagot importáljuk, neve a szimbólumkészletbe kerül és közvetlenül elérhetővé válik. Ennek nem egészen ajánlott változata a from <modulnév> import *
utasítás, mely az összes tag nevét a szimbólumkészletbe írja. Hátránya, hogy ha sok modult használunk, nem fogjuk tudni, mit honnan importáltunk.
Fájlkezelés
A Python természetesen támogatja a szöveges és bináris fájlok kezelését is. A kezelendő fájl megnyitása az open() függvénnyel történik, melynek visszatérése egy fájl objektum. Megnyitás után ezen objektum metódusainak hívásával tudjuk a fájlt kezelni. Az open() függvény két paramétert vár: a megnyitandó fájl elérési útját (lehet direkt és relatív is), valamint a megnyitás módját (r = olvasás, w = írás, a = folytatás). Bináris fájl megnyitása hasonlóan történik, különbség csupán a megnyitás módjában jelentkezik, a módokhoz hozzá kell írni egy „b” betűt (tehát rb, wb, ab). Szöveges fájl beolvasás 3 módon lehetséges:
- bejárjuk a fájl sorait, mint egy listát (f a fájlváltozónk):
for sor in f:
print sor
- a read() metódussal egyben olvassuk be – egy stringbe – a teljes fájl tartalmát:
szoveg = f.read()
print szoveg
- A read() metódusnak lehet egy egész típusú paramétere, ekkor n karaktert olvas be a fájlból (ahol n az egész paraméter)
- a readlines() metódus a fájl soraiból egy listát készít:
szoveg = f.readlines()
for sor in szoveg:
print szoveg
Bináris fájlokban megtudhatjuk, hol áll éppen a „fájlkurzor” a tell() metódus meghívásával. Keresni a seek() metódussal tudunk, mely két paramétert vár: az első megadja, hogy a fájl-kurzor hány bájtot mozduljon el. A második paraméter azt határozza meg, hogy ez az elmozdulás mihez képest történjen, ami 3 féle lehet:
- 0: abszolút pozíció (a fájl-kurzor a fájl elejétől n bájtot lép előre, ahol n az első paraméter értéke)
- 1: relatív elmozdulás az aktuális pozíciótól (x. pozícióról az x + n-edik pozícióra lép)
- 2: relatív elmozdulás a fájl végétől (ekkor n értelemszerűen negatív érték kell, hogy legyen) Az olvasást/írást a read() illetve a write() metódusokkal valósítjuk meg, előbbinek opcionális paramétere a beolvasandó adatmennyiség bájtban.
Ha befejeztük a fájl feldolgozását, ne felejtsük el lezárni a close() metódus meghívásával! Ezt azonban elkerülhetjük, ha a „with” szerkezetet használjuk (példa látható majd rá a példaprogramban). Ez a C# „using(…)” illetve a Java „try(…)” szerkezetéhez hasonlóan, amennyiben olyan erőforrást kap, amely automatikusan bezárható, akkor a with szerkezet „blokkjának” végén az erőforrás bezárásra kerül. Hátránya, hogy ez a módszer csak a Python 2.7-es verziójától áll rendelkezésünkre.
Kivételkezelés
Bár a Python meglehetősen rugalmas nyelv, természetesen Python scriptjeink is ráfuthatnak nem várt eseményekre, azaz kivételekre. Aki már írt Java, C# vagy akár PHP alatt kivételkezelőt, annak nem lesz meglepő a Python kivétel-kezelési mechanizmusa sem. Az ellenőrizni kívánt utasításokat egy try blokkban helyezzük el, a kivételeket azonban itt az except ágakon tudjuk elkapni. Ugyanúgy van finally ág is, az ebben megadott utasítások akár volt kivétel, akár nem, mindenképp lefutnak. Egyszerűbb kivételkezelőt írhatunk a nyelv saját, beépített kivételtípusai segítségével is, ekkor az except ágakra csak a megfelelő kivételtípusokat kell írnunk (vesszővel elválasztva egy ág akár több típust is el tud kapni). A beépített kivételtípusokról a nyelv hivatalos dokumentációjából tájékozódhatunk. Saját kivételosztályt is készíthetünk, ehhez természetesen ismernünk kell a nyelv objektum-orientált utasításkészletét és lehetőségeit, így erre később, annak tárgyalása során még visszatérek. Kivétel kiváltása a raise utasítással lehetséges.
Haladó rendezés
A listákon alkalmazhatunk saját rendezőalgoritmust is elemeinek rendezéséhez, de használhatjuk a beépített sorted függvényt is. Numerikus és szöveges adatokat tartalmazó listák rendezésére egyaránt alkalmas, utóbbi esetben lexikografikus rendezést alkalmaz. A sorted-nek 3 opcionális paramétere lehet:
reverse=True
: fordított rendezéscmp=<összehasonlító_függvény>
: egy olyan összehasonlító függvényt vár (paraméterlista nélkül), mely egy-egy paraméterben kapja meg a két összehasonlítandó elemet, visszatérése pedig egy egész szám (a = b esetén 0, a > b esetén pozitív, a < b esetén pedig negatív). A Python 3.x verziója már nem használja.key=<kulcsfüggvény>
: egy speciális „kulcsfüggvényt” kell átadnunk a key paraméternek, mely azt határozza meg, hogy mi alapján és hogyan rendezzünk. Így például lehetővé válik egy szótár rendezése is, vagy akár egy string-beli rész-string szerint is rendezhetünk. Használhatunk beépített függvényeket is, például a key=len paraméter megadásával a lista elemeinek hossza szerint rendezhetünk, vagy a key=str.lower paraméterrel case-insensitive rendezést érhetünk el. A megadott függvénynek mindenképp egy paraméteres függvénynek kell lennie!
URL-ek kezelése
A Python haladóbb eszközei közé tartozik az URL-ek kezelése. Az URL-kezelő függvények használatához importálnunk kell az urllib
és az urllib2
nevű modulokat. Egy cím megnyitását az urlopen metódussal tehetjük meg. Megnyitásakor a kért címet a háttérben megnyitja a nyelv, és az oldal HTML forrását egy objektumba menti, melynek tartalmához a read() metódussal férhetünk hozzá. Egy változóba mentve az oldal forrását, azon bármilyen stringműveletet elvégezhetünk, illetve bejárhatjuk a forrást soronként. Lehetőségünk van egy fájl letöltésére is az urlretrieve
metódus használatával. Az első paraméter a letöltendő fájl címe, a második paraméter a célfájl elérési útvonala (természetesen fájlnévvel együtt).
JSON fájlok kezelése
JSON fájlokban tudunk perzisztens módon tárolni (összetett) adatszerkezeteket. Egyfajta adatbázisként használhatjuk őket, néhány alapvető adattípust ismer (numerikus és logikai értékek, stringek, tömbök, szótárak, objektumok). Használatához importálnunk kell a json
csomagot. A nyelv a következő jelöléseket alkalmazza:
- { … } kapcsos zárójelek között egy objektumot definiálunk
- [ … ] szögletes zárójelek között tömböt jelölünk.
- az objektum mezőinek nevét idézőjelek között adjuk meg
- a mezők szöveges értékeit idézőjelek közé tesszük, a numerikus értékeket további jelölések nélkül adjuk meg, logikai érték esetén pedig a true vagy a false kulcsszót használjuk
- értékadás kettősponttal történik, a mezőket vesszővel választjuk el.
JSON fájlt két módon nyithatunk meg:
- amennyiben már egy, a gépünkön létező json fájlt szeretnénk használni, egyszerűen, mint szöveges fájlt megnyitjuk az open() függvénnyel, majd a load() függvénynek átadva a fájlváltozót;
- vagy ha egy string változóban tároljuk a JSON információit (például urlopen() segítségével mentettük le), akkor a loads() függvénynek átadva a stringváltozót.
A nyelv mindkét esetben létrehozza a JSON fájl által meghatározott teljes adatszerkezetet, amely tetszőlegesen mély és bonyolult lehet. Ekkor a változó tartalmának hozzáférése körülményessé válhat, mivel több egymásba ágyazott tömböt (listát) és szótárat is tartalmazhat. Ilyenkor érdemes használni a neten fellelhető JSON vizualizációs eszközöket, így könnyebb megérteni a létrejövő adatszerkezet struktúráját.
A dumps()
függvény a megadott adatszerkezetből (pl.: szótár) egy JSON szerkezetet készít. A dump függvény segítségével írhatjuk fájlba a JSON szerkezetet. 4 paramétert vár, amiből 2 opcionális:
- az első a kiírandó adatszerkezet változója
- a második egy fájlváltozó, amibe kiírjuk a JSON szerkezetet
- a harmadik (opcionális) paraméter (indent) formázza a JSON stringet, a bekezdéseket a megfelelő szintekre igazítja
- a negyedik (opcionális) paraméter (sort_keys) értékét True-ra állítva az adatszerkezetet a kiírás előtt a kulcsok szerint rendezi (ez persze csak szótár esetén lehetséges).
Reguláris kifejezések
Reguláris kifejezéseket az re
modul importálásával nyílik lehetőségünk használni. Konkrétan ezen cikk keretein belül most nem szeretnék kitérni, mik a reguláris kifejezések. A search függvénnyel tudunk keresni egy stringben illeszkedő mintázatokat. Két paramétert vár: mit és miben. A létrejövő objektum group() metódusával tudunk hozzáférni a találatokhoz. Ellenőrizhető, hogy volt-e találat: a search() által létrehozott objektum úgy vizsgálható, mint egy logikai érték: ha volt találat, akkor „igaz”, különben „hamis” (értéke None) . A mintázat megadásánál mindig érdemes használni a mintastring előtt az „r” módosítót, így a mintát mint nyers stringet dolgozza fel (az escape szekvenciákat figyelmen kívül hagyja).
A search() függvény csak egy találatot ad vissza, így amennyiben több illeszkedést is keresünk, a findall() függvényt kell használnunk. Ez egy listát ad vissza. Amennyiben a mintában használunk zárójeleket (tehát az illeszkedő stringnek bizonyos részeire van szükségünk), úgy tuple-ök listáját adja.
A findall() függvénynek lehet egy opcionális paramétere, amivel a keresésnek bizonyos funkcionalitásokat adhatunk. Például jelezhetjük vele a case-insensitive keresési módot (re.IGNORECASE).
Természetesen részstring cseréjére is lehetőségünk van a sub függvény használatával. Három paramétert vár: mit, mire és miben. Van egy negyedik opcionális paramétere is, amivel megadható, hány illeszkedést cseréljen le. Visszahivatkozásokhoz a 1, 2, … szekvenciákat használhatjuk.
A reguláris kifejezések esetén találkozhatunk a „mohó illesztés” fogalmával, amit a Pythonban is a „?” karakter hozzáadásával szüntethetünk meg. (Megjegyzés: mohó az illesztés, ha a minta mondjuk két részre osztható, és a minta két vége között is megtalálható a teljes mintázat, akkor a legszélesebb illeszkedést fogja választani).
#!/usr/bin/env python
# coding: utf-8
# a karakterkódolás miatt van szükség a következő 3 sorra
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
# normál importálás, a modulokban levő tagokat minősítéssel érjük el (pl.: json.load())
import re
import json
import urllib
import urllib2
# importálással alias-szal (a tagok minősítése az alias-szal történik)
import sys as rendszer # sys.argv helyett rendszer.argv
# csak bizonyos tagok importálása
from re import search #innentől a search függvény használható minősítés nélkül
# fájlkezelés kivételkezeléssel
def fajlkezelesKivetelkezelessel():
# tegyük az összes itteni utasítást egy nagy kivételkezelő blokkba
try:
# megnyitás klasszikus módszerrel
f = open('peldaJSON.json', 'r')
# bejárás soronként
for sor in f:
print sor
# ilyenkor explicit módon le kell zárnunk a fájlt!
f.close()
# megnyitás with szerkezettel - a példa kedvéért szándékosan kivételt okozok
with open('peldaJSON_.json', 'r') as f:
# beolvasás listába - a fájl sorai lesznek a lista elemei
szoveg = f.readlines()
print szoveg
#ilyenkor nem kell lezárni a fájlt, mert a with szerkezet megteszi helyettünk
# másolás új fájlba, egy menetben (read metódussal)
with open('peldaJSON.json', 'r') as inFile, open('masolat.txt', 'w') as outFile:
szoveg = inFile.read()
outFile.write(szoveg)
# lezárni itt sem kell az írásra megnyitott fájlt sem, mert a with szerkezet itt is megteszi helyettünk
except IOError as ex:
# ez az ág csak az IO hibákat fogja elkapni, amit mondjuk itt a fájl megnyitása okozhat (ha nem létezik a fájl)
print 'IO hiba történt!'
print 'A kivétel oka: {0}'.format(ex)
except Exception as ex:
# általános kivételkezelő ág, minden kivételt elkap
print 'Általános kivétel történt!'
print 'A kivétel oka: {0}'.format(ex)
finally:
# az ebben az ágban levő utasítások mindenképp lefutnak
print 'Lefutott a kivételkezelő'
# a beépített sorted rendező függvény összetett használata
def haladoRendezes():
li = ['alfa', 'beta', 'gamma', 'delta', 'epsilon']
# rendezés fordított sorrendben:
print sorted(li, reverse=True)
# rendezés cmp paraméterrel - segédfüggvény: cmpRendezes(x, y)
print sorted(li, cmp=cmpRendezes)
#rendezés key paraméterrel - segédfüggvény: keyRendezes(s)
print sorted(li, key=keyRendezes)
# segédfüggvény a rendezéshez (cmp paraméterhez)
def cmpRendezes(x, y):
if x < y:
return -1
elif x > y:
return 1
else:
return 0
# segédfüggvény a rendezéshez (key paraméterhez)
def keyRendezes(s):
# legyen a rendezés kulcsa a string harmadik karaktere, vagy ha a string rövidebb, mint 3 karakter, akkor az első karaktere
if len(s) > 2:
return s[2]
else:
return s[0]
# az URL kezelés alapvető eszközei
def URLkezeles():
# url megnyitása, és a tartalom kiolvasása - a példa kedvéért csak az első 20 karaktert olvasom be
url = urllib2.urlopen('http://psprog.hu/kapcsolat')
tartalom = url.read(20)
print tartalom
# letöltés - kommentbe téve, hogy ne fusson le :)
#urllib.urlretrieve('http://psprog.hu/dl/mytux_small.jpg', 'peldafajl.jpg')
# JSON kezelés
def JSONkezeles():
try:
# megnyitjuk olvasásra a json fájlt
with open('peldaJSON.json', 'r') as f, open('outF.json', 'w') as outF, open('outF2.json', 'w') as outF2:
# a json modul load függvényével parse-oljuk az állomány tartalmát, mint json forrást
cikk = json.load(f)
# a mellékelt példában egy szótárat implementáltam, melynek van string, logikai, egész értékű, valamint egy tömböt tartalmazó mezője
print "A cikk adatai:\n\tCím: {cim}\n\tTerjedelem: {hossz} oldal\n\tVan melléklet: {melleklet}".format(cim=cikk['cim'], hossz=cikk['oldalak'], melleklet=('igen' if cikk['melleklet'] else 'nem'))
print "\tCímkék: ",
for cimke in cikk['cimkek']:
print cimke + ",",
print
# a példában szereplő "cimkek" tömb tartalmát kiírjuk egy json fájlba:
# 4 szóközre állítjuk a behúzást
json.dump(cikk['cimkek'], outF, indent=4)
# az eredeti json fájlt kiírjuk egy új állományba, kulcsok szerinti rendezéssel
json.dump(cikk, outF2, indent=4, sort_keys=True)
except IOError:
print "Töltsd le a peldaJSON.json mellékletet!"
# reguláris kifejezések használata
def regExp():
szoveg = """Ebben a szövegben keresünk egy email címet ami@ez.lesz, szóval reméljük, meg is találja majd a kifejezés,
de a példa kedvéért elrejtek@meg.egyet, ezzel teszteljük majd a findall() funkcionalitását."""
# a következő mintával megengedjük tetszőleges szó-karakter jelenlétét, de megkötjük, hogy szerepelnie kell a mintában
# @ illetve . karakternek, illetve a . utáni rész 2-5 karakter hosszúságú kell legyen
# a zárójelezéssel a . előtti részstringre külön tudunk hivatkozni
minta = r'([\w]+@[\w]+)\.[\w]{2,5}'
talalat = re.search(minta, szoveg)
# mivel a group() kivételt dob, ha nincs találat a mintára, ezért tegyük egy feltételbe az egészet
if talalat:
# mivel a search() függvény csak az első találatig keres, a group() egyetlen elemmel tér vissza
print "Találat: " + talalat.group()
# annak viszont hivatkozhatunk (mivel 1 db zárójelpárunk van) 2 db elemére: a teljes illeszkedő stringre,
# illetve a bezárójelezett részstringre
print "Teljes illeszkedő string: " + talalat.group(0)
print "Bezárójelezett részstring: " + talalat.group(1)
else:
print "Nincs illeszkedő részstring"
# a findall() függvény használatával megkereshetjük az ÖSSZES illeszkedő részstringet
# a példa kedvéért módosítsunk a mintán: szedjük szét a címet a . mentén
minta = r'([\w]+@[\w]+)\.([\w]{2,5})'
talalat = re.findall(minta, szoveg)
# a findall() által visszaadott lista elemei így tuple-ök lesznek: minden egyes eleme egy olyan tuple lesz,
# melynek első eleme a . előtti rész, második eleme a . utáni rész
print "Összes illeszkedő részstring: " + str(talalat)
# utolsó példaként cseréljük le a cím . utáni tagját "hu"-ra
csere = r'\1.hu'
szoveg = re.sub(minta, csere, szoveg)
print "Csere után: " + szoveg
def main():
print ' --- Fájlkezelés kivételkezelővel ---'
fajlkezelesKivetelkezelessel()
print '\n\n --- Haladó rendezés ---'
haladoRendezes()
print '\n\n --- URL kezelés ---'
URLkezeles()
print '\n\n --- JSON kezelés ---'
JSONkezeles()
print '\n\n --- Reguláris kifejezések használata ---'
regExp()
if __name__ == "__main__":
main()
JSON példafájl a cikk példaprogramjához (a script használja ezt a fájlt!)
{
"cim": "A Python hasznos eszközei 2",
"oldalak": 4,
"melleklet": true,
"cimkek": ["Python", "Script", "Programozás"]
}
Komment írásához jelentkezz be
Bejelentkezés
Még senki nem szólt hozzá ehhez a bejegyzéshez.