6. gyakorlat¶
A gyakorlat anyaga¶
Ezen a gyakorlaton a cloc nevű eszközt (elérhető ezen a linken) fogjuk hívogatni Pythonból. Azért ezt, mert ad valami outputot, amivel aztán majd tudunk valamit kezdeni.
A cloc (count lines of code) egy ingyenes program, ami annyit tud, hogy egy fájlról, vagy mappáról megmondja, hogy milyen nyelvű forrásból mennyi kódsor, komment sor, üres sor található.
Az, hogy mit hívogatunk az órán, az tetszőleges, bármit lehet lokálisan használni, a feladat viszont ehhez az eszközhöz kapcsolódik.
Aki nem szeretné betelepíteni és a PATH
-ból használni, az teljes elérési úttal is meghívhatja.
Debug alapok¶
- Breakpoint elhelyezése a kódban
- Feltételes breakpoint elhelyezése a kódban
- Kivétel breakpoint elhelyezése a kódban
- Futás közbeni kiértékelés
Subprocess¶
A subprocess modul segítségével (is) meghívhatunk másik alkalmazásokat Pythonból. Python 3.5 óta a run
metódus használata a javasolt a korábbi változatok (pl.: call
) helyett.
A modul leírása: https://docs.python.org/3/library/subprocess.html
import subprocess
if __name__ == '__main__':
# subprocess.run(["help"])
# subprocess.run(["echo", "Húsvéti nyúl"])
subprocess.run(["echo", "Húsvéti nyúl"], shell=True)
subprocess.run(["cloc", "utils"])
cp = subprocess.run(["cloc", "utils"])
print(cp)
if cp.returncode == 0:
print("A program futása sikeres volt!")
print("--- capture_output")
cp = subprocess.run(["cloc", "utils"], capture_output=True)
print(cp)
print("--- capture_output és text")
cp = subprocess.run(["cloc", "utils"], capture_output=True, text=True)
print(cp)
print("stdout", len(cp.stdout))
print("stderr", len(cp.stderr))
# Ha a returncode nem 0, itt egy CalledProcessError dobódik
cp.check_returncode()
# Ha az output nem érdekel
cp = subprocess.run(["cloc", "utils"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=1)
print(cp)
try:
cp = subprocess.run(["python", "-c", "import time; time.sleep(2)"], timeout=1)
except subprocess.TimeoutExpired as cpe:
print("A program nem lett kész időben!")
cp = subprocess.run(["python", "-c", "print('Valamiéáőúű')"], stdout=subprocess.PIPE)
print(cp.stdout)
print(type(cp.stdout))
print(cp.stdout.decode('utf-8'))
print("--- input átadása")
subprocess.run(["python", "-c", "print(input())"], input=b"Cica")
subprocess.run(["python", "-c", "print(input())"], input="Valamiéáőúű".encode('utf-8'))
print("--- stdin fájlból")
with open("parancsok.txt", "r", encoding="utf8") as fp:
subprocess.run(["python", "-c", "for i in range(2): print(input())"], stdin=fp)
print("--- stdout fájlba")
with open("zen_gondolatok.txt", "w", encoding="utf8") as fp:
subprocess.run(["python", "-c", "import this"], stdout=fp)
# cwd=None
# check=False - ugyanaz, mint a visszateresi objektum check_returncode() metódusa
# encoding=None, errors=None, text=None
# env=None
# universal_newlines=None
argparse¶
import argparse
parser = argparse.ArgumentParser()
parser.version = '1.0'
parser.add_argument('-a', action='store', metavar='ALMAK_SZAMA')
parser.add_argument('-b', action='store_const', const=42)
parser.add_argument('-c', action='store_true')
parser.add_argument('-d', '--direkt-hamis', action='store_false')
parser.add_argument('-e', action='append')
parser.add_argument('-f', action='append_const', const=42)
parser.add_argument('-g', action='count', help="Mennyire nehéz az argparse használata")
parser.add_argument('-i', action='help')
parser.add_argument('-j', action='store', default="Jaj ne")
parser.add_argument('-v', action='version')
parser.add_argument('--input', action='store', type=int, nargs=3)
parser.add_argument('-x', action='count', required=True)
parser.add_argument('-p', choices=("alma", "körte", "barack"))
my_group = parser.add_mutually_exclusive_group()
my_group.add_argument('--verbose', action='store_true')
my_group.add_argument('--silent', action='store_true')
args = parser.parse_args()
print(args)
print(vars(args))
Collections¶
namedtuple¶
Egyszerű, nevesített tuple, hasonló a C-beli struct típushoz.
import collections
# Named tuples
Varazslo = collections.namedtuple("Varazslo", ['nev', 'haj_szin', 'haj_meret', 'szem_szin'])
harry = Varazslo("Harry Potter", "barna", "rövid", "zöld")
ron = Varazslo("Ron Weasly", "vörös", "rövid", "vörös")
hermione = Varazslo("Hermione Granger", "barna", "hosszú", "barna")
print(harry)
print("név", harry.nev)
print("név", harry[0])
print("harry dict", harry._asdict())
print("---")
print(ron)
ron = ron._replace(szem_szin="barna")
print(ron)
print("---")
malfoy_dict = {'nev': 'Draco Malfoy', 'haj_szin': 'szőke', 'haj_meret': 'rövid', 'szem_szin': 'kék'}
malfoy = Varazslo(**malfoy_dict)
print(malfoy)
piton_list = ["Perselus Piton", "fekete", "félhosszú", "barna"]
piton = Varazslo._make(piton_list)
print(piton)
# Ki kicsoda játék készítése
Counter¶
Egy ügyes dict
leszármazott, ami képes elemek leszámolására.
import collections
jegyeim = [1, 3, 5, 5, 3, 2, 4, 5, 2, 2, 3, 4, 5, 5, 1, 5, 5, 3, 4, 3, 2, 1]
# Counter (ősosztálya a dict)
counter = collections.Counter(jegyeim)
print(counter.items())
print(counter.most_common())
counter.subtract([1, 1, 1])
print(counter)
deque¶
Két irányból láncolt sor. Gyakorlatilag olyan lista, amibe lehet mindkét irányba beszúrni és törölni.
import collections
# Deque
deque = collections.deque(["a", "b", "c"])
deque.append("d")
deque.appendleft("z")
print(deque)
deque.pop()
deque.popleft()
print(deque)
Adatosztályok¶
- Python 3.7 óta
import dataclasses
import random
@dataclasses.dataclass()
class Varazslo:
nev: str
haj_szin: str
haj_meret: str
szem_szin: str
def __str__(self):
return f"Varazslo(nev={self.nev}, haj_szin={self.haj_szin}, haj_meret={self.haj_meret}, szem_szin={self.szem_szin}"
def varazsol(self):
if "Ron" in self.nev:
return "Leviossz" + ("á" * random.randint(6, 15))
return "Leviósza"
if __name__ == '__main__':
harry = Varazslo("Harry Potter", "barna", "rövid", "zöld")
ron = Varazslo("Ron Weasly", "vörös", "rövid", "vörös")
hermione = Varazslo("Hermione Granger", "barna", "hosszú", "barna")
print(ron.varazsol())
print(hermione.varazsol())
itertools¶
Az itertools
modul sok olyan hasznos függvényt tartalmaz, amik iterátorokkal térnek vissza. Hasznos, memóriabarát módja ez az elembejárásnak (és generálásnak).
count¶
import itertools
for i in itertools.count(5, 5):
if i == 35:
break
else:
print(i, end=" ")
print("\n---")
repeat¶
import itertools
print("Jó sokszor megismételjük a legszebb számot")
print(list(itertools.repeat(2, 4)))
print("\n---")
zip¶
import itertools
szinek = ["sárga", "kék", "zöld", "barna", "piros"]
targyak = ["autó", "motor", "ház", "gomba"]
print(list(zip(szinek, targyak)))
print(list(itertools.zip_longest(szinek, targyak)))
print(list(itertools.zip_longest(szinek, targyak, fillvalue="valami")))
combinations/permutations¶
import itertools
hallgatok = ["Harry Potter", "Ron Weasly", "Hermione Granger", "Ginny Weasley", ]
# "Tom Denem", "Sirius Black", "Dudley Dursley", "Albus Dumbledore",
# "Luna Lovegood", "Draco Malfoy", "Rubeus Hagrid", "Parvati Patil",
# "Neville Longbottom", "Romilda Vane"]
print("-- kombinációk")
print(list(itertools.combinations(hallgatok, 3)))
print(list(itertools.combinations_with_replacement(hallgatok, 3)))
print("-- permutációk")
print(list(itertools.permutations(hallgatok)))
cycle¶
import itertools
hallgatok = ["Harry Potter", "Ron Weasly", "Hermione Granger", "Ginny Weasley", ]
print("-- ciklizálás")
count = 0
for i in itertools.cycle(hallgatok):
print(i)
count += 1
if count == 100:
break
product¶
lapok = ['A', 'K', 'Q', 'J', '10', '9', '8', '7', '6', '5', '4', '3', '2']
szinek = ['H', 'D', 'C', 'S'] # hearts, diamonds, clubs, and spades
def pakli():
for lap in lapok:
for szin in szinek:
yield lap, szin
pakli_0 = pakli()
pakli_1 = ((lap, szin) for szin in szinek for lap in lapok)
pakli_2 = itertools.product(lapok, szinek)
print(list(pakli_0))
print(list(pakli_1))
print(list(pakli_2))
chain¶
hallgatok_1 = ["Harry Potter", "Ron Weasly", "Hermione Granger", "Ginny Weasley"]
hallgatok_2 = ["Tom Denem", "Sirius Black", "Dudley Dursley", "Albus Dumbledore"]
print(itertools.chain(hallgatok_1, hallgatok_2))
print(list(itertools.chain(hallgatok_1, hallgatok_2)))
Órai feladatok¶
Megjegyzés
Az órai feladatok alatt lévő feladat(sor)ok azok a feladat(sor)ok, amelyek megoldása beleszámít a zh javításért megoldandó feladatok közé. Ezen feladat(sor)okból 6 darab megoldása szükséges ahhoz, hogy egy zh javíthatóvá váljon. Ha külön nem jelezzük, a teljes feladatsor megoldása esetén jár a zh javításért szerezhető pont.
Info
A teljes feladatsor megoldása szükséges a zh javításért járó pont megszerzéséért.
CLOC okosító¶
-
Készítsd el a
run_cloc
nevű függvényt, ami egy fájl útvonalát várja paraméterben. A függvény futtassa le acloc
eszközt a megadott forrásfájlra, asubprocess
segítségével. A kimenetet kapd el, és figyelj rá, hogy maximum 5 másodpercig várj a függvény futására. A kimenetet a felhasználónak ne is írja ki, hanem csak tárold le. A letárolt outputot dolgozd fel az alábbiak szerint: készítsd egy dataclasst vagy namedtuple típust, ami a következőeket tárolja:path
,language
,code
,comment
,blank
. Ezek pedig az eszköz kimenetéből kiolvasott adatok legyenek, az útvonalat kivéve, mert azt a függvény paramétereként kapjuk meg. A feldolgozás végén térj vissza ezzel a feltöltött objektummal. -
Készíts egy
loc
nevű függvényt az adatosztályba (vagy globálisloc
nevű függvényt, ha namedtuple-t használtál). Ez adja össze egy objektum kódsorait, kommenteit és üres sorait, ezzel megállapítva, hogy hány soros ténylegesen a fájl. -
Készíts
run_cloc_dir
nevű függvényt, ami egy mappa útvonalat vár, és a mappában lévő összes függvényre meghívja arun_cloc
függvényt, majd az eredményeiket egy listában visszaadja. A függvénynek legyen egyrecursive
paramétere, ami megadja, hogy a mappán belül rekurzívan kell-e az összes fájl, vagy csak közvetlenül a mappában lévő fájlokat szeretnénk listázni. -
Készíts egy
max_loc
nevű függvényt, ami egy mappanevet, és arecursive
paramétert várja. Használja fel arun_cloc_dir
nevű függvényt, de az eredményeket dolgozza fel. A megírtloc
függvény segítségével válaszd ki, hogy melyik az a fájl, amelyikben a legtöbb sor kód van, és ennek nevével térj vissza. -
Készíts egy
loc_by_lang
nevű függvényt, ami egy mappanevet, és arecursive
paramétert várja. Használja fel arun_cloc_dir
nevű függvényt, de az eredményeket dolgozza fel. A metódus adja össze, hogy melyik nyelvből mennyi volt az összes kódsor (nem a teljes loc). Ezzel a dictionaryvel térjen vissza. -
Készíts parancssori paraméter beolvasót az alábbi kapcsolókkal:
-p
: egy útvonal, ahol kell futnia a toolnak (lehet mappaa vagy fájl is), szöveges típusú.-r
: egy igen/nem, ami megmondja, hogy rekurzív legyen-e a keresés.-m, --max
: egy igen/nem, ami megmondja, hogy csak a legtöbb sorból álló fájlra vagyunk-e kíváncsiak (max_loc
). Nem működhet együtt a--stat
kapcsolóval.--stat
: egy igen/nem, ami megmondja, hogy a statisztikát kérünk-e (loc_by_lang
). Nem működhet együtt a--max
kapcsolóval.-s
: az eredmények mentése csv fájlban. A kapcsoló várja a kimeneti útvonalat, ami szöveges típusú.