Fájlműveletek és command line

Megmutatjuk, hogy önálló Python scriptek hogyan kezelik a bemeneti paramétereiket és hogyan tudunk fájlokat írni és olvasni

Fájl olvasása

A Python - ahogyan a legtöbb programnyelv - a fájlokat egy fájl objektumon keresztül olvassa és írja. Nézzük meg, hogy hogyan működik!

In [ ]:
f = open('E0.csv')
print f

Egyelőre ez csak egy fájl objektum. A mintafájlunk az angol Premier League 2015/16-os idényének a statisztikáit tartalmazza. Most olvassunk is valamit! Az f.read() kiolvassa a fájlt teljes tartalmát egy sztringbe. Nem printeljük ki az egészet, mert túl sok.

In [ ]:
f = open('E0.csv')
content = f.read()
print content[:100]

Olvassuk ki most csak az első sort!

In [ ]:
f = open('E0.csv')
first_line = f.readline()
print first_line
second_line = f.readline()
print second_line

Ez még mindig nagyon fárasztó. Szerencsénk van, hogy erre is gondoltak a fejlesztők, hiszen a fájl objektum iterálható.

In [ ]:
f = open('E0.csv')
L = []
for line in f:
    L.append(line)
print L[20]    

Így most van egy L listánk, ami a fájl sorait tartalmazza. GGWP.

Fájl írása

Képzeljük el, hogy Liverpool szurkolók vagyunk és nekünk csak a kedvenc csapatunk eredményei számítanak. Írjuk ki egy fájlba őket! Az olvasáshoz hasonlóan szükségünk lesz egy fájl objektumra, de ahhoz, hogy írni tudjuk, másként kell megnyitni. Először egy egyszerű példa. Az open(filename, 'wb') írásra nyitja meg a fájlt, de ha írunk, vigyázzunk, hogy zárjuk is be!

In [ ]:
f = open('Liverpool.csv', 'wb')
f.write('YNWA')
f.close()

Megjegyzés: olvasáshoz az open('E0.csv', 'rb') parancsot illik használni, de alapvetően olvasásra nyitunk meg egy fájlt. Most térjünk vissza az eredeti példához! Soronként beolvassuk a fájlt, és ahol a Liverpool adata szerepel, elmentjük. Ne felejtsük el, hogy a fejlécre továbbra is szükségünk van!

In [ ]:
f = open('E0.csv')
L = [f.readline()]
for line in f:
    if 'Liverpool' in line:
        L.append(line)
with open('Liverpool.csv', 'wb') as f:
    for l in L:
        f.write(l)
f.close()

Python, csv és json

Az előző fájl .csv kiterjesztése a comma separated values-re utal. Az ilyen fájlokban egy sorban egy rekord szerepel, a rekordok adatait pedig vesszővel - nem feltétlenül, választhatunk más karaktert pl. tab, pontosvessző stb. - választjuk el. Mivel ez meglehetősen kényelmes formája az adatok tárolásának, a Pythonnal könnyű kezelni az ilyen fájlokat. Erre való a csv modul. A with open(filename, 'rb') as f pontosan ugyanahhoz az eredményhez vezet mintha f = open(filename, 'rb')-t írtunk volna. Ha lehet, használjuk az utóbbit, hiszen így pontosan látjuk, meddig olvassuk a fájlunkat!

In [ ]:
import csv
L=[]
with open('E0.csv', 'rb') as csvfile:
    reader = csv.reader(csvfile, delimiter=',', quotechar='"')
    for row in reader:
        L.append(row)
print L[0]
print L[19]

A különbség szembetűnő. A csv.reader egyből listát csinál nekünk a sorokból. Ráadásul megadhatjuk neki az elválasztó karaktert, valamint a quotechar-t is, ami az idézőjel karaktert jelöli ki. Ez azért fontos néhány esetben, mert sokszor számok és sztringek vegyesen vannak egy csv fájlban, ilyenkor a sztringeket idézőjelbe szokták tenni, amit érdemes felismernünk.

csv olvasása szótárba

Ha jól megnézzük az adatokat, nekünk nem feltétlenül listákra lenne szükségünk, hanem szótárakra. A fájl ugyanis minden meccsre ugyanazokat az adatokat tárolja, mi pedig szívesebben hivatkozunk indexek helyett nevekkel dolgokra. Erre is van lehetőség.

In [ ]:
import csv
L=[]
with open('E0.csv', 'rb') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        L.append(row)
print L[0]        

Tároljuk most el a Liverpool mérkőzéseinek legfontosabb adatait. Ezek a 'Date', 'HomeTeam', 'AwayTeam', 'FTHG'(Full Time Home Goals), 'FTAG' (Full Time Away Goals), 'FTR' (Full Time Result)! A tároláshoz a csv.DictWriter lesz segítségünkre. a writer.writeheader() a fejlécet írja ki fájlba, a writer.writerows() pedig egy mozdulattal kiírja az összes adatunkat. A fieldnames paraméterben adhatjuk meg, hogy milyen attribútumokra van szükségünk, az extrasaction='ignore' pedig pusztán azért kell, hogy a többi adatot ne írja bele.

In [ ]:
import csv
L=[]
with open('E0.csv', 'rb') as csvfile:
    reader = csv.DictReader(csvfile)
    for x in reader:
        if x['HomeTeam'] == 'Liverpool' or x['AwayTeam'] == 'Liverpool':
            L.append(x)
csvfile.close()
with open('Liverpool.csv', 'wb') as output:
    fields = ['Date', 'HomeTeam', 'AwayTeam', 'FTHG', 'FTAG', 'FTR']
    writer = csv.DictWriter(output, fieldnames=fields, extrasaction='ignore')
    writer.writeheader()
    writer.writerows(L)
output.close()

A json formátum

JavaScript Object Notation. tárolhatunk benne számokat, sztringeket, listát, szótárat. Sőt, tetszőlegesen egymásba ágyazhatunk szótárakat, listákat, listák listáját, szótárak listáját, szótárak szótárát, listák szótárát. Listák elemeit vesszővel választjuk el, a szótárakat pedig mint a Pythonban key:value módon adjuk meg. { "Liverpool" : { "Players": [ "Steven Gerrard", "Bill Shankly" ], "Results" : [ { "HomeTeam":"Liverpool", "AwayTeam":"Tottenham", "HTG":1, "ATG":1 }, { "HomeTeam":"West Ham", "AwayTeam":"Liverpool", "HTG":2, "ATG":0 } ], "Points":1, "Goals Scored":1, "Goals Condceded":3 } }

Természetesen a Pythonnal a json-t is kényelmesen lehet kezelni. Egyszerűen beolvassuk a fájlt és kiírjuk a képernyőre. Látjuk, hogy Python szótár keletkezett belőle, tehát hivatkozhatunk a kulcsaira. Az u'Steven Gerrard' azt jelenti, hogy unicode sztringet olvastunk be.

In [ ]:
import json
with open('Liverpool.json') as data_file:    
    data = json.load(data_file)

print data
print data['Liverpool']['Players']

Írjuk ki egy fájlba a meccsek eredményeit! A külalakra is figyelünk, erre való a sort_keys, az indent és a separators. A json.dumps(obj) tetszőleges Python objectet json sztringgé alakít, így ezt egyszerűen kiírjuk a fájlba!

In [ ]:
import json
with open('Liverpool.json') as data_file:    
    data = json.load(data_file)
data_file.close()
with open('Liverpool_matches.json', 'wb') as f:
    f.write(json.dumps(data['Liverpool']['Results'], sort_keys=True, indent=4, separators=(',', ': ')))

Command line argumentumok

Nézzük meg az egyszerű esetet. Elmentünk .py végződéssel egy fájlt. Ezt a rendszer felismeri mint Python scriptet. El tudjuk indítani a konzolon belül, de az ipython is tudja kezelni. Egyelőre csak kiírjuk a bemeneti paraméterek listáját. Az első elem mindig a script neve. A paramétereket a sys.argv listában tárolja a Python. Ehhez kell az import sys. Minden argumentum string.

Jelen esetben a %run pusztán azért kell, hogy szimulálni tudjuk, milyen is a Unix command line.

In [ ]:
%run hello.py arg1 arg2

Egy fokkal - csak egy fokkal - bonyolultabban. Írjuk ki a bementi paraméter négyzetét. Az ilyen paramétereket hívjuk pozicionális paramétereknek, hiszen a sys.argv listában elfoglalt helyük alapján azonosítjük őket. Most emeljünk egy számot adott hatványra!

In [ ]:
%run square.py 4.2 3

argparse

A sys.argv tömböt is feldolgozhatjuk, de ezt is megtette helyettünk már valaki. Az argparse modul segít nekünk egészen komplex command line paraméterek beolvasásában is. Nézzünk példát egy flag-re. Ezek kvázi kétállípotú kapcsolók, amelyek befolyásolják a kód működését, nézzünk egy példát a verbosity-re. Ha a felhasználó szeretné, követheti a lépéseket.

In [ ]:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbosity", help="increase output verbosity")
args = parser.parse_args()
if args.verbosity:
    print "verbosity turned on"
In [ ]:
%run parser.py --verbosity 1
In [ ]:
%run parser.py

Ez minden egész értéket elfogad a --verbosity után. Még ennél is elegánsabb az action='store_true'. Most ráadásul elég csak -v-vel meghívni

In [ ]:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", help="increase output verbosity", action="store_true")
args = parser.parse_args()
if args.verbose:
   print "verbosity turned on"
In [ ]:
%run parser2.py
%run parser2.py --verbose
%run parser2.py -v

Sőt, a help menü automatikusan elkészül. Ehhez kellett a help="increase output verbosity".

In [ ]:
%run parser2.py --help

Vissza a csv fájlunkhoz. Szeretnénk megtudni, hogy egy adott csapatnak hány olyan mérkőzése volt, amelyen legalább x gólt rúgott. A csapat nevét és a gólok számát is olvassuk be a parancssorból! Az action='store' az args szótár megdelelő kulcsához társítja az értéket, a type pedig meghatározza a típusát. Megjegyezzük, hogy ezek az argumentumok opcionálisak, így nem árt, ha alapértelmezett értéke is van (default).

In [ ]:
import argparse
import csv

parser = argparse.ArgumentParser()
parser.add_argument("-t", "--team", help="The team we are looking for", action="store", type=str, default='Liverpool')
parser.add_argument("-g", "--goals", help="Number of minimum goals scored", action="store", type=float, default=0)
args = parser.parse_args()

m = 0
team = args.team
goals = args.goals
with open('E0.csv', 'rb') as csvfile:
    reader = csv.DictReader(csvfile)
    for x in reader:
        if x['HomeTeam'] == team and float(x['FTHG']) >= goals:
            m += 1
        elif x['AwayTeam'] == team and float(x['FTAG']) >= goals:
            m += 1
print m
In [ ]:
%run goals.py -h
In [ ]:
%run goals.py -g 1
In [ ]: