11. Listák

A lista értékek rendezett gyűjteménye. Azokat az értékeket, amelyek a listát alkotják elemeknek nevezzük. A listák hasonlóak a sztringekhez, amelyek a karakterek rendezett gyűjteményei, kivéve, hogy a lista elemei bármilyen típusúak lehetnek. A listákat és a sztringeket – és más gyűjteményeket, amelyek megőrzik az elemek sorrendjét – sorozatnak nevezzük.

11.1. A lista értékei

Többféle módon lehetséges egy új lista létrehozása; legegyszerűbb az elemek szögletes zárójelbe való felsorolása ([ és ]):

1
2
ps = [10, 20, 30, 40]
qs = ["alma", "eper", "barack"]

Az első példa egy lista, amely négy egész számot tartalmaz. A második lista pedig három sztringet tartalmaz. A lista elemeinek nem kell azonos típusúnak lennie. A következő lista tartalmaz egy szrtinget, egy valós számot, egy egész számot és (érdekességképpen) egy másik listát.

1
zs = ["hello", 2.0, 5, [10, 20]]

A listában szereplő másik listáról azt mondjuk, hogy beágyazott.

Végül azt a listát, amely nem tartalmaz elemeket, üres listának nevezzük, és [] jelöljük.

Ahogyan már korábban láthattuk, a változókhoz vagy a listákhoz tartozó listaértékeket paraméterként hozzárendelhetjük a függvényekhez:

1
2
3
4
szotar = ["alma", "sajt", "kutya"]
szamok = [17, 123]
ures_lista = []
print(szotar, szamok, ures_lista)
["alma", "sajt", "kutya"] [17, 123] []

11.2. Elemek elérése

A listaelemek elérésének szintaktikája hasonló, mint a sztringek esetében – az index operátort használjuk: [] (ne tévesszük össze az üres listával). A zárójelben lévő kifejezés adja meg az indexet. Emlékezzünk arra, hogy az indexek 0-tól kezdődnek:

1
print(szamok[0])
17

Bármilyen egész értéket visszaadó kifejezés használható indexként:

1
print(szamok[9-8])
123
1
print(szamok[1.0])
Traceback (most recent call last):
   File "<input>", so 1, in <module>
TypeError: list indices must be integers or slices, not float

Ha egy olyan elemet akarunk elérni, amely nem létezik, futási idejű hibát kapunk:

1
print(szamok[2])
Traceback (most recent call last):
   File "<input>", line 1, in <module>
IndexError: list index out of range

Használhatjuk a ciklusváltozót lista indexként.

1
2
3
4
lovasok = ["háború", "éhínség", "pestis", "halál"]

for i in [0, 1, 2, 3]:
    print(lovasok[i])

A cikluson belül minden alkalommal az i változót használjuk a lista i. elemének kiírtatására. Ezt az algoritmust nevezzük lista bejárásnak.

A fenti példa esetén nem szükséges vagy nem használja az i indexet semmire, csak az elemek elérésére, így ez a direktebb verzió – ahol a for ciklus megkapja az elemeket – kedveltebb lehet:

1
2
3
4
lovasok = ["háború", "éhínség", "pestis", "halál"]

for h in lovasok:
    print(h)

11.3. A lista hossza

A len függvény visszatér a lista hosszával, amely egyenlő a lista elemeinek számával. Amennyiben egy egész indexet használunk a lista eléréséhez, célszerűbb, ha a lista hosszát használjuk a ciklus felső értékeként egy konstans helyett. Így, ha a lista mérete megváltozik, nem szükséges végig követni a teljes programot és módosítani az összes ciklust, mivel bármilyen méretű lista esetén megfelelően fog működni:

1
2
3
4
lovasok = ["háború", "éhínség", "pestis", "halál"]

for i in range(len(lovasok)):
    print(lovasok[i])

Az ciklus utolsó végrehajtása esetén, i értéke a len(lovasok)-1, amely az utolsó elem indexe. (De az index nélküli változat jobban néz ki!).

Habár a lista egy másik listát is tartalmazhat, a beágyazott lista egyetlen elemként szerepel a szülői listában.

A lista hossza 4:

1
2
hossz = len(["autó gyártók", 1, ["Ford", "Toyota", "BMW"], [1, 2, 3]])
print(hossz)
4

11.4. Lista tagság

Az in és a not in Boolean típusú operátorok, amelyek megvizsgálják egy elem tagságát a sorozatban. Korábban a sztringeknél már használtuk, de listákkal és más sorozatokkal is működnek:

1
2
3
4
5
lovasok = ["háború", "éhínség", "pestis", "halál"]

print("pestis" in lovasok)
print("dezertálás" in lovasok)
print("dezertálás" not in lovasok)

Az eredmény a következő:

True
False
True

Ez a módszer sokkal elegánsabb a beágyazott ciklusoknál, amit korábban az Informatikára jelentkezett hallgatók számának meghatározásához használtunk a Beágyazott ciklus beágyazott adatokhoz fejezetben:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
hallgatok = [
    ("Jani", ["Informatika", "Fizika"]),
    ("Kata", ["Matematika", "Informatika", "Statisztika"]),
    ("Peti", ["Informatika", "Könyvelés", "Közgazdaságtan", "Menedzsment"]),
    ("Andi", ["Információs Rendszerek", "Könyvelés", "Közgazdaságtan", " Vállalkozási Jog"]),
    ("Linda", ["Szociológia", "Közgazdaságtan", "Jogi ismeretek", "Statisztika", "Zene"])]

# Számold meg, hány hallgató vette fel az Informatikát.
szamlalo = 0
for (nev, targyak) in hallgatok:
    if "Informatika" in targyak:
           szamlalo += 1

print("Az Informatikát felvett hallgatók száma:", szamlalo)

11.5. Lista műveletek

A + operátor összefűzi a listákat:

1
2
3
4
a = [1, 2, 3]
b = [4, 5, 6]
c = a + b
print(c)
[1, 2, 3, 4, 5, 6]

Hasonlóképpen, a * operátor megismétli a listát egy megadott számszor:

1
2
3
4
d = [0] * 4
print(d)
e = [1, 2, 3] * 3
print(e)
[0, 0, 0, 0]
[1, 2, 3, 1, 2, 3, 1, 2, 3]

Az első példában [0]-t négyszer ismétli. A második példában az [1, 2, 3] listát háromszor ismétli meg.

11.6. Lista szeletek

A szeletelő operátorok, ahogyan korábban a sztringeknél is láthattuk, működnek részlisták esetében is:

1
2
3
4
5
a_list = ["a", "b", "c", "d", "e", "f"]
print(a_list[1:3])
print(a_list[:4])
print(a_list[3:])
print(a_list[:])

Az eredmény a következő:

['b', 'c']
['a', 'b', 'c', 'd']
['d', 'e', 'f']
['a', 'b', 'c', 'd', 'e', 'f']

11.7. A listák módosíthatók

A sztringektől eltérően a listák módosíthatók, ami azt jelenti, hogy megváltoztathatjuk az elemeiket. Az értékadás bal oldalán az index operátor használatával az egyik elemet módosíthatjuk.

1
2
3
4
gyumolcs = ["banán", "alma", "eper"]
gyumolcs[0] = "körte"
gyumolcs[2] = "narancs"
print(gyumolcs)
['körte', 'alma', 'narancs']

A zárójel operátor a listákra alkalmazva bárhol megjelenhet egy kifejezésben. Ha a kifejezés bal oldalán jelenik meg, akkor megváltoztatja a lista egyik elemét, így a gyumolcs lista első eleme fog cserélődni "banán"-ról "körte"-re, és az utolsó eleme pedig "eper"-ről "narancs"-ra. Az elem listához való hozzárendelését indexelt értékadásnak nevezzük. Az indexelt értékadás nem működik a sztringek esetében:

1
2
sajat_sztring = "ADAT"
sajat_sztring[3] = "G"
Traceback (most recent call last):
    File "<input>", line 1, in <module>
TypeError: 'str' object does not support item assignment

de a listák esetében igen:

1
2
3
sajat_lista = ["A", "D", "A", "T"]
sajat_lista[3] = "G"
print(sajat_lista)
['A', 'D', 'A', 'G']

A szeletelő operátor használatával módosíthatjuk a teljes részlistát:

1
2
3
 a_list = ["a", "b", "c", "d", "e", "f"]
 a_list[1:3] = ["x", "y"]
 print(a_list)
['a', 'x', 'y', 'd', 'e', 'f']

Az elemeket a listából eltávolíthatjuk úgy, hogy hozzárendelünk egy üres listát:

1
2
3
a_list = ["a", "b", "c", "d", "e", "f"]
a_list[1:3] = []
print(a_list)
['a', 'd', 'e', 'f']

Hozzáadhatunk a listához elemeket úgy, hogy beszúrjuk őket egy üres szeletre a kívánt helyen:

1
2
3
a_list = ["a", "d", "f"]
a_list[1:1] = ["b", "c"]
print(a_list)
['a', 'b', 'c', 'd', 'f']
1
2
a_list[4:4] = ["e"]
print(a_list)
['a', 'b', 'c', 'd', 'e', 'f']

11.8. Lista törlése

A szeletek használata a lista törlésére hibát adhat. A Python egy jobban olvasható alternatívát is kínál. A del utasítás eltávolít egy elemet a listából:

1
2
3
a = ["egy", "kettő", "három"]
del a[1]
print(a)
['egy', 'három']

A del utasítás futási idejű hibát ad vissza, amennyiben az index kívül esik a tartományon.

A del-t használhatjuk egy szelettel, hogy kitöröljünk egy részlistát:

1
2
3
a_list = ["a", "b", "c", "d", "e", "f"]
del a_list[1:5]
print(a_list)
['a', 'f']

A szokásos módon a szelet által választott részlista tartalmazza az összes elemet az első indextől kezdődően, de már nem tartalmazza a második indexű elemet.

11.9. Objektumok és hivatkozások

Miután végrehajtjuk az értékadó utasításokat:

1
2
a = "banán"
b = "banán"

látjuk, hogy az a és b a "banán" sztring objektumra utal. De még nem tudjuk, hogy ugyanarra a sztring objektumra mutatnak-e.

Két lehetséges módja van annak, hogy a Python kezelje a memóriát:

Lista illusztráció

Az első esetben a és b két különböző objektumra hivatkozik, amelyek azonos értékűek. A második esetben ugyanarra az objektumra hivatkoznak.

Az is operátor segítségével megvizsgálhatjuk, hogy a két név ugyanarra az objektumra hivatkozik-e:

1
print(a is b)
True

Azt mutatja, hogy az a és b ugyanarra az objektumra hivatkozik, továbbá, hogy a második a két pillanatnyi állapot közül az, amely pontosan leírja a kapcsolatot.

Mivel a sztringek megváltoztathatatlanok, a Python úgy optimalizálja az erőforrásokat, hogy létrehoz két nevet, amely ugyanarra a sztringre, ugyanarra az objektumra hivatkozik.

Ez nem áll fenn a listák esetében:

1
2
3
4
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)
print(a is b)
True
False

Az aktuális állapot a következőképpen néz ki:

Pillanatkép két különböző lista egyenlőségéről

a és b-nek ugyanaz az értéke, de nem ugyanarra az objektumra hivatkoznak.

11.10. Fedőnevek

Mivel a változók objektumokra hivatkoznak, ha egy változót hozzárendelünk egy másikhoz, mindkét változó ugyanarra az objektumra fog hivatkozni:

1
2
3
a = [1, 2, 3]
b = a
print(a is b)
True

Ebben az esetben a pillanatnyi állapot a következőképpen néz ki:

Pillanatkép többszörös lista hivatkozásra (fedőnevek)

Mivel ugyanazon a listára két különböző névvel hivatkozunk, a-val és b-vel, azt mondjuk, hogy ők fedőnevek. A fedőneveken végrehajtott változtatások hatással vannak egymásra.

1
2
b[0] = 5
print(a)
[5, 2, 3]

Habár ez a tulajdonság hasznos, néha kiszámíthatatlan és nemkívánatos. Általában biztonságosabb elkerülni a fedőnevek használatát, amikor módosítható objektumokkal dolgozunk (például: a tankönyvünk ezen pontján lévő felsorolások, továbbá több módosítható objektummal is fogunk találkozni, osztályokkal és objektumokkal, szótárakkal és halmazokkal). Természetesen a megváltozhatatlan objektumok (például: sztringek, rendezett n-esek) esetén nincs probléma – tehát a fedőneveket nem lehetséges csak úgy megváltoztatni. Ezért a Python szabadon ad fedőnevet a sztringeknek (és bármilyen más megváltozhatatlan adat típusoknak), amikor lehetőséget lát a takarékoskodásra.

11.11. Listák klónozása

Ha módosítani szeretnénk egy listát, és az eredeti példányát is meg szeretnénk őrizni, szükséges egy másolatot készíteni a listáról, nem csak a hivatkozásról. Ezt a folyamatot klónozásnak nevezzük, hogy elkerüljük a másolás szó kétértelműségét.

A lista klónozásának legegyszerűbb módja a szelet operátor használata:

1
2
3
a = [1, 2, 3]
b = a[:]
print(b)
[1, 2, 3]

Az a bármelyik szeletével egy új listát hozhatunk létre. Ebben az esetben a szelet tartalmazza a teljes listát. Tehát most a kapcsolat a következőképpen néz ki:

Pillanatkép két különböző lista egyenlőségéről

Most szabadon megváltoztathatjuk b-t anélkül, hogy aggódnánk attól, hogy véletlenül megváltoztatjuk az a-t:

1
2
b[0] = 5
print(a)
[1, 2, 3]

11.12. Listák és a for ciklus

A for ciklus működik a listákkal is, ahogyan már korábban láthattuk. A for ciklus általánosított szintaxisa:

for VÁLTOZÓ in LISTA:
    TÖRZS

Tehát, ahogy láttuk:

1
2
3
baratok = ["Péter", "Zoli", "Kata", "Zsuzsa", "Tamás", "József", "Sándor"]
for barat in baratok:
    print(barat)

Bármely lista kifejezés használható egy for ciklusban:

1
2
3
4
5
6
for szam in range(20):
    if szam % 3 == 0:
        print(szam)

for filmek in ["vígjáték", "animációs", "romantikus"]:
    print("Én szeretem a " + filmek + "et!")

Az első példa kiírja a 3 szám összes többszörösét 0 és 19 között. A második példa a különféle filmek iránti rajongást fejezi ki.

Mivel a listák módosíthatók, gyakran a listát szeretnénk bejárni, megváltoztatva minden elemét. A következő példában az xs lista összes elemét négyzetre emeljük:

1
2
3
4
xs = [1, 2, 3, 4, 5]

for i in range(len(xs)):
    xs[i] = xs[i]**2

Vessünk egy pillantást a range(len(xs)) utasításra, amíg meg nem értjük, hogy működik!

Ebben a példában mind az elem értéke (négyzetre akarjuk emelni az értékeket), mind pedig az indexe (az új értéket hozzárendeljük a pozícióhoz) érdekel bennünket. Ez a minta elég gyakori, a Python szebb módot ajánl ennek megvalósítására.

1
2
3
4
xs = [1, 2, 3, 4, 5]

for (i, ert) in enumerate(xs):
    xs[i] = ert**2

Az enumerate (index, érték) párokat generál a lista bejárás során. Próbáld ki a következő példát, hogy jobban megértsd az enumerate működését!

1
2
for (i, v) in enumerate(["banán", "alma", "körte", "citrom"]):
     print(i, v)
0 banán
1 alma
2 körte
3 citrom

11.13. Lista paraméterek

Ha egy listát argumentumként átadunk, akkor hivatkozni fog a listára, nem egy másolatot vagy klónt készít a listáról. Tehát a paraméterátadásra egy fedőnevet hoz létre: a hívónak van egy változója, mely a listára hivatkozik, és a hívott függvénynek van egy fedőneve, de alapvetően csak egy lista objektum van. Például az alábbi függvény argumentuma egy lista, mely a listának minden elemét megszorozza 2-vel:

1
2
3
4
def megduplaz(a_list):
    """ Átírjuk a lista minden elemét a kétszeresére. """
    for (idx, ert) in enumerate(a_list):
        a_list[idx] = 2 * ert

Ha a szkripthez hozzáadjuk a következőket:

1
2
3
b_list = [2, 5, 9]
megduplaz(b_list)
print(b_list)

Amikor futtatjuk a következő eredményt kapjuk:

[4, 10, 18]

A fenti függvényben az a_list paraméter és a b_list változó ugyanazon objektum fedőnevei. Tehát a listában szereplő elemek módosítása előtt a lista állapota a következőképpen néz ki:

_images/mult_references4.png

Mivel a lista objektum meg van osztva két keretre, a listát ezek közé írtuk. Ha egy függvény módosítja a lista paramétereinek elemeit, akkor a hívó látja a módosítást.

Használjuk a Python megjelenítőt!

A Python megjelenítő egy nagyon hasznos eszköz, mely segítséget nyújt a hivatkozások, fedőnevek, értékadások és a függvény argumentumok átadásának megértéséhez. Különös figyelmet kell fordítani azokra az esetekre, amikor egy listát klónozunk vagy két külön listánk van, valamint amikor csak egy alapvető lista szerepel, de egynél több fedőneves változó hivatkozik a listára.

11.14. Lista metódusok

A pont operátor is használható a lista objektumok beépített metódusainak elérésére. Kezdjük a leghasznosabb metódussal, amellyel hozzáadhatunk valamit a lista végéhez:

1
2
3
4
5
6
sajat_lista = []
sajat_lista.append(5)
sajat_lista.append(27)
sajat_lista.append(3)
sajat_lista.append(12)
print(sajat_lista)
[5, 27, 3, 12]

Az append lista metódus hozzáfűzi a megadott argumentumot a lista végéhez. Gyakran használjuk új lista készítésénél. A következő példával bemutatjuk néhány további lista metódus használatát.

Szúrjuk be a 12-t az 1-es pozícióra, eltolva a többi elemet!

1
2
sajat_lista.insert(1, 12)
print(sajat_lista)
[5, 12, 27, 3, 12]

Hány 12-es érték szerepel a listában?

1
 print(sajat_lista.count(12))
2

Szúrjuk be a teljes listát a sajat_lista végére!

1
2
sajat_lista.extend([5, 9, 5, 11])
print(sajat_lista)
[5, 12, 27, 3, 12, 5, 9, 5, 11]

Keressük meg az első 9-es érték indexét a listában!

1
print(sajat_lista.index(9))
6

Fordítsuk meg a listát!

1
2
sajat_lista.reverse()
print(sajat_lista)
[11, 5, 9, 5, 12, 3, 27, 12, 5]

Rendezzük a listát!

1
2
sajat_lista.sort()
print(sajat_lista)
[3, 5, 5, 5, 9, 11, 12, 12, 27]

Rendezzünk egy szöveges adatokat tartalmazó listát!

1
2
3
4
5
6
szoveg_lista = ["barack", "alma", "mandarin"]
szoveg_lista.sort()
print(szoveg_lista)
szoveg_lista2 = ["én", "te", "ő", "mi", "ti", 'ők']
szoveg_lista2.sort()
print(szoveg_lista2)
['alma', 'barack', 'mandarin']
['mi', 'te', 'ti', 'én', 'ő', 'ők']

A második listára kapott eredménnyel valószínűleg nem vagyunk elégedettek. Mivel a rendezés az elemek összehasonlításán alapul, ezért azt kell megoldanunk, hogy a hasonlítás az általunk kívánt módon történjen meg:

1
2
3
4
5
6
7
import locale
import functools

locale.setlocale(locale.LC_ALL, "HU_hu.UTF8")  # a nyelv és a kódolás beállítása
szoveg_lista2 = ["én", "te", "ő", "mi", "ti", 'ők']
szoveg_lista2.sort(key = functools.cmp_to_key(locale.strcoll))
print(szoveg_lista2)

A korábbiakban a sort metódust paraméter nélkül használtuk. Most a key paraméter segítségével megadjuk, hogy az strcoll hasonlítsa össze az elemeket, mely figyelembe veszi a 4. sorban beállított környezetet. Most már nem okoznak problémát az ékezetes karakterek.

['én', 'mi', 'ő', 'ők', 'te', 'ti']

Távolítsuk el az első 12-es értéket a listából!

1
2
sajat_lista.remove(12)
print(sajat_lista)
[3, 5, 5, 5, 9, 11, 12, 27]

Kísérletezz és játssz az itt bemutatott lista metódusokkal, és olvasd el a rájuk vonatkozó dokumentációkat, addig, amíg nem vagy biztos benne, hogy megértetted hogyan működnek.

11.15. Tiszta függvények és módosítók

Azok a függvények, amelyek argumentumként egy listát kapnak, és módosítják a listát a végrehajtás során módosítónak, és az általuk végrehajtott változtatásokat pedig mellékhatásnak nevezzük.

A tiszta függvény nem eredményez mellékhatásokat. A tiszta függvény a hívó programmal csak a paramétereken keresztül kommunikál, amelyeket nem módosít, és visszaad egy értéket. Itt a megduplaz egy tiszta függvényként van megírva:

1
2
3
4
5
6
7
8
def megduplaz(a_list):
    """ Visszaad egy listát, mely az a_list elemeinek kétszeresét tartalmazza. """
    uj_list = []
    for ertek in a_list:
        uj_elem = 2 * ertek
        uj_list.append(uj_elem)

    return uj_list

Ez a megduplaz változat nem változtatja meg a függvény argumentumait:

1
2
3
4
b_list = [2, 5, 9]
xs = megduplaz(b_list)
print(b_list)
print(xs)
[2, 5, 9]
[4, 10, 18]

Egy korábbi szabály szerint, amely az értékadásra vonatkozott „először kiértékeljük a jobb oldalt, majd hozzárendeljük az eredményt a változóhoz”. Tehát elég biztonságos a függvény eredményét ugyanahhoz a változóhoz rendelni, melyet átadtunk a függvénynek:

1
2
3
b_list = [2, 5, 9]
b_list = megduplaz(b_list)
print(b_list)
[4, 10, 18]

Melyik stílus a jobb?

Bármi, amit a módosítókkal meg lehet tenni az tiszta függvényekkel is elvégezhető. Valójában egyes programozási nyelvek csak tiszta függvényeket engedélyeznek. Van néhány bizonyíték arra, hogy azok a programok, melyek tiszta függvényeket használnak gyorsabbak, és kevesebb hibalehetőséget tartalmaznak, mint a módosítókat használók. Mindazonáltal a módosítók néha kényelmesek, és egyes esetekben a funkcionális programok kevésbé hatékonyak.

Általánosságban azt javasolják, hogy tiszta függvényeket írjunk, és csak akkor alkalmazzuk a módosítókat, ha nyomós okunk van rá, és előnyünk származik belőle. Ezt a megközelítést funkcionális programozási stílusnak nevezzük.

11.16. Listákat előállító függvények

A fent említett megduplaz tiszta verziója egy fontos mintát használ az eszköztárából. Amikor egy listát létrehozó és visszaadó függvényt kell írni, a minta általában:

1
2
3
4
5
inicializálja az eredmény változót, legyen egy üres lista
ciklus
    hozzon létre egy új elemet
    fűzze hozzá az eredményhez
return eredmény

Mutassuk be egy másik használati módját ennek a mintának! Tegyük fel, hogy már van egy primszam(x) függvényünk, amely teszteli, hogy az x prímszám-e. Írj egy függvényt, amely visszaadja az összes n-nél kisebb prímszámot:

1
2
3
4
5
6
7
def prim_kisebbmint(n):
    """ Visszaadja az összes n-nél kisebb prímszámot. """
    eredmeny = []
    for i in range(2, n):
        if primszam(i):
        eredmeny.append(i)
    return eredmeny

11.17. Szrtingek és listák

A két leghasznosabb metódus a sztringek esetében a részsztringek listájának (oda és vissza) konverziója. A split metódus (melyet már korábban láthattunk) szétválasztja a sztringet szavak listájába. Alapértelmezés szerint bármilyen számú whitespace karakter tekinthető szóhatárnak:

1
2
3
nota = "Esik eső, szép csendesen csepereg..."
szavak = nota.split()
print(szavak)
['Esik', 'eső,', 'szép', 'csendesen', 'csepereg...']

Az opcionálisként megadott argumentumot határolónak nevezzük, amely meghatározza, hogy mely karakterlánc legyen a határ a részsztringek között. A következő példában az se sztring határolót használjuk:

1
print(nota.split("se"))
['Esik eső, szép c', 'nde', 'n c', 'pereg...']

Figyeljük meg, hogy a határoló nem jelenik meg az eredményben.

A split metódus inverze a join metódus. Kiválaszthatjuk a kívánt határoló sztringet (gyakran ragasztónak nevezik), és összefűzhetjük a lista minden egyes elemét a ragasztóval.

1
2
3
ragaszto = ";"
s = ragaszto.join(szavak)
print(s)
'Esik;eső,;szép;csendesen;csepereg...'

Az összeillesztett lista (a példában szereplő szavak) nem módosul. Továbbá, amint ez a következő példa is mutatja, használhatunk üres vagy több karakterből álló sztringet ragasztóként:

1
print(" -- ".join(szavak))
'Esik -- eső, -- szép -- csendesen -- csepereg...'
1
print("".join(szavak))
'Esikeső,szépcsendesencsepereg...'

11.18. A list és a range

A Python egy list nevezetű beépített konverziós függvénnyel rendelkezik, amely megpróbál bármit listává alakítani.

1
2
3
xs = list("Mocsári Béka")
print(xs)
print("".join(xs))
['M', 'o', 'c', 's', 'á', 'r', 'i', ' ', 'B', 'é', 'k', 'a']
'Mocsári Béka'

A range egyik tulajdonsága az, hogy nem számolja ki rögtön az összes értéket: „félre teszi” a számolást, és csak kérésre végzi el, azaz „lustán”. Mondhatni ígéretet ad rá, hogy amikor szükségünk lesz egy elemre, akkor elő fogja azt állítani. Ez nagyon kényelmes, ha a számításunk rövidzáras keresés, és korábban visszatér az értékkel, mint a következő esetben:

1
2
3
4
5
6
7
8
def f(n):
""" Keresse meg az első pozitív egész számot 101 és n között, amely osztható 21-el. """
for i in range(101, n):
    if (i % 21 == 0):
        return i

teszt(f(110) == 105)
teszt(f(1000000000) == 105)

A második teszt-ben, ha a range fel lenne töltve a lista összes elemével, gyorsan kihasználná a számítógép memóriáját, és a program összeomlana. De ennél okosabb! Ez a számítás jól működik, mert a range objektum csak ígéret ad az elemek előállítására, amikor szükséges. Amint a ha feltétel igazzá válik, nem generál további elemeket, és a függvény visszatér. (Megjegyzés: A Python 3 előtt a range nem volt lusta. Ha a Phython korábbi verzióját használja, YMMV!)

YMMV: Your Mileage May Vary (A kilométer teljesítményed változhat)

A YMMV rövidítés azt jelenti, hogy a kilométer teljesítményed változhat. Az amerikai autós hirdetések gyakran megemlítették az autók üzemanyag-felhasználási adatait, például, hogy az autó gallonként 28 mérföldet tehet meg. De ezt mindig egy apró-betűs jogi résznek kell kísérnie, figyelmeztetve az olvasót, hogy lehet nem fognak ugyanannyit kapni. Az YMMV kifejezést a köznyelvben úgy használjuk, hogy „az eredmények eltérhetnek”, például A telefon akkumulátorának élettartama 3 nap, de YMMV.

Néha találkozhattuk a lusta range-el, amely egy list hívásába van beágyazva. Ez arra kényszeríti Pythont, hogy a lusta ígéretét egy listává változtassa:

1
2
print(range(10))           # Hozzon létre egy lusta ígéretet
print(list(range(10)))     # Hívja meg az ígéretet, mely létrehozza a listát

Az eredmény a következő:

range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

11.19. Beágyazott listák

A beágyazott lista olyan lista, amely egy másik listában elemként jelenik meg. Ebben a listában a 3. indexű elem egy beágyazott lista:

1
beagyazott = ["hello", 2.0, 5, [10, 20]]

Ha a lista 3. elemét kiírjuk a következőt kapjuk:

1
print(beagyazott[3])
[10, 20]

Ha a beágyazott listának egy elemét ki akarjuk íratni, ezt két lépésben tehetjük meg:

1
2
elem = beagyazott[3]
print(elem[0])
10

Vagy kombinálhatjuk őket:

1
print(beagyazott[3][1])
20

A zárójel operátor kiértékelése balról jobbra történik, tehát a kifejezés megkapja a beagyazott lista 3. elemének első elemét.

11.20. Mátrixok

A beágyazott listákat gyakran használják a mátrixok ábrázolásánál. Például legyen a következő mátrix:

_images/matrix2.png

amit ábrázolni lehet, mint:

1
mx = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

mx egy három elemű lista, mely mindegyik eleme a mátrix egy sora.

A mátrixból egy teljes sort kiválaszthatunk a szokásos módon:

1
print(mx[1])
[4, 5, 6]

Vagy kiválaszthatunk egy elemet a mátrixból,a kettős-indexet használva:

1
print(mx[1][2])
6

Az első index kiválasztja a sort, a második pedig az oszlopot. Habár a mátrixok ábrázolásának ezen módja a gyakoribb, ez nem az egyetlen lehetőség. Kevesebb változatot használhatunk az oszlopok listájára, mint a sorokra. Később további radiálisabb alternatívát fogunk látni a szótár használatával.

11.21. Szójegyzék

beágyazott lista (nested list)
Egy lista, amelynek egy eleme egy másik lista.
elem (element, item)
Egy érték a listából. A szögletes zárójel operátor segítségével választjuk ki az elemet a listából.
fedőnevek (aliases)
Több változó, amelyek ugyanazon objektumra hivatkoznak.
határoló (delimiter)
Olyan karakter vagy karakterlánc, amely jelzi, hol kell szétválasztani egy sztringet.
index (index)
Egy egész szám, amely jelöli egy elem listán belüli pozícióját. Az indexek 0-tól kezdődnek.
ígéret (promise)
Egy olyan objektum, amely megígéri, hogy valamilyen munkát elvégez vagy valamilyen értéket kiszámol, ha szükség van rá, de lustán végzi el a munkát (nem azonnal). A range hívása ígéretet eredményez.
klónozás (clone)
Új objektum létrehozása, melynek ugyanaz az értéke, mint egy meglévő objektumnak. Egy objektumra mutató hivatkozás másolása fedőnevet hoz létre, de nem klónozza az objektumot.
lépésköz (step size)
A lineáris sorozatban az egymást követő elemek közötti intervallum. A range függvénynek a harmadik (és opcionális) argumentumát lépés méretnek nevezzük. Ha nincs megadva, az alapértelmezett értéke 1.
lista (list)
Értékek gyűjteménye. Mindegyik értéknek meghatározott helye van a listában. Más típusokhoz hasonlóan str, int, float, stb. van egy list típus-átalakító függvény is, amely bármely argumentumát listává próbálja alakítani.
lista bejárás (list traversal)
A lista minden egyes elemének sorrendben történő elérése.
mellékhatás (side effect)
Egy program állapotának megváltoztatása a hívó függvény által. A mellékhatásokat csak módosítókkal lehet előállítani.
minta (pattern)
Utasítások sorozata vagy olyan kódolási stílus, amely általánosan alkalmazható számos különböző helyzetben. Érett informatikussá válik az, aki megtanulja, létrehozza az eszközkészletet alkotó mintákat és algoritmusokat. A minták gyakran megfelelnek a mentális blokkosításnak.
módosítható adat típusok (mutable data value)
Olyan adat értékek, amelyek módosíthatók. Minden módosítható értéktípus összetett. A listák és szótárak módosíthatók, a sztringek és a rendezett n-esek nem.
módosító (modifier)
Olyan függvény, amely megváltoztatja az argumentumokat a függvény törzsében. Csak a módosítható típusok változtathatók meg.
objektum (object)
Egy „dolog”, amelyre egy változó hivatkozhat.
sorozat (sequence)
Bármilyen olyan adat típus, mely rendezett elemeket tartalmaz, és minden elemet egy index-el azonosítunk.
tiszta függvény (pure function)
Olyan függvény, mely nem okoz mellékhatásokat. A tiszta függvények csak a visszatérítési értékekkel okozhatnak változást a hívó függvényben.
változtathatatlan adat érték (immutable data value)
Olyan adatérték, amelyet nem lehet módosítani. Az értékadások a megváltoztathatatlan elemek vagy szeletek esetén futási idejű hibát okoznak.

11.22. Feladatok

  1. Mi lesz a Python kód eredménye a következő utasítás esetén?

    list(range(10, 0, -2))
    

    A range függvény három argumentuma a start, stop és step. Ebben a példában a start nagyobb, mint a stop. Mi történik, ha a start < stop és a step < 0? Írj egy szabályt a start, a stop és a step közötti kapcsolatokra.

  2. Tekintsük a következő kódrészletet:

    1
    2
    3
    4
    5
    import turtle
    
    Eszti = turtle.Turtle()
    Sanyi = Eszti
    Sanyi.color("hotpink")
    

    Ez a kódrészlet egy vagy két teknőc példányt hoz létre? A Sanyi színének megváltoztatása Eszti színét is meg fogja változtatni? Magyarázd el részletesen!

  3. Rajzolj az a és b számára egy pillanatképet, a következő Python kód 3. sorának végrehajtása előtti és utáni állapotában:

    1
    2
    3
    a = [1, 2, 3]
    b = a[:]
    b[0] = 5
    
  4. Mi lesz a következő programrészlet kimenete?

    1
    2
    3
    4
    5
    ez = ["Én", "nem", "vagyok", "egy", "csodabogár"]
    az = ["Én", "nem", "vagyok", "egy", "csodabogár"]
    print("Test 1: {0}".format(ez is az))
    ez = az
    print("Test 2: {0}".format(ez is az))
    

    Adj részletes magyarázatot az eredményekről.

  5. A listákat használhatjuk matematikai vektorok ábrázolására. Ebben és az ezt követő néhány gyakorlatban olyan függvényeket írunk le, amelyek végrehajtják a vektorok alapvető műveleteit. Hozz létre egy vectorok.py szkriptet, és írd bele az alábbi Python kódot, hogy mindegyiket letesztelhesd!

    Írj egy vektorok_osszege(u, v) függvényt, amely paraméterként két azonos hosszúságú listát kap, és adjon vissza egy új listát, mely tartalmazza a megfelelő elemek összegét:

    1
    2
    3
    teszt(vektorok_osszege([1, 1], [1, 1]) == [2, 2])
    teszt(vektorok_osszege([1, 2], [1, 4]) == [2, 6])
    teszt(vektorok_osszege([1, 2, 1], [1, 4, 3]) == [2, 6, 4])
    
  6. Írj egy szorzas_skalarral(s, v) függvényt, amely paraméterként egy s számot, és egy v listát kap, és visszatér a függvény a v lista s skalárral való szorzatával.

    1
    2
    3
    teszt(szorzas_skalarral(5, [1, 2]) == [5, 10])
    teszt(szorzas_skalarral(3, [1, 0, -1]) == [3, 0, -3])
    teszt(szorzas_skalarral(7, [3, 0, 5, 11, 2]) == [21, 0, 35, 77, 14])
    
  7. Írj egy skalaris_szorzat(u, v) függvényt, amely paraméterként megkap két azonos hosszúságú számokat tartalmazó listát, és visszaadja a megfelelő elemek skaláris szorzatát.

    1
    2
    3
    teszt(skalaris_szorzat([1, 1], [1, 1]) ==  2)
    teszt(skalaris_szorzat([1, 2], [1, 4]) ==  9)
    teszt(skalaris_szorzat([1, 2, 1], [1, 4, 3]) == 12)
    
  8. Extra matematikai kihívások: Írj egy vektorialis_szorzat(u, v) függvényt, amely paraméterként megkap két 3 hosszúságú számokból álló listát, és visszatér a vektoriális szorzatukkal. Írd meg a saját tesztjeid!

  9. Írd le a " ".join(nota.split()) és nota közötti kapcsolatot az alábbi kódrészletben. Ugyanazok a sztringek vannak hozzárendelve a nota-hoz? Mikor lennének különbözőek?

    1
    nota = "Esik eső, szép csendesen csepereg..."
    
  10. Írj egy cserel(s, regi, uj) függvényt, amely kicseréli a regi összes előfordulását a uj-ra az s szrtingben.

    1
    2
    3
    4
    5
    6
    7
    8
    teszt(cserel("Mississippi", "i", "I") == "MIssIssIppI")
    
    s = "Kerek a gömb, gömbszerű!"
    teszt(cserel(s, "öm", "om") ==
        "Kerek a gomb, gombszerű!")
    
    teszt(cserel(s, "o", "ö") ==
        "Kerek a gömb, gömbszerű!")
    

    Tipp: Használd a split és join metódusokat.

  11. Tegyük fel, hogy két változó értékét akarjuk felcserélni. Újra felhasználható függvényt hozz létre, írd bele az alábbi kódot:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    def csere(x, y):      # Hibás változat
        print("csere utasítás előtt: x:", x, "y:", y)
        (x, y) = (y, x)
        print("csere utasítás után: x:", x, "y:", y)
    
    a = ["Ez", "nagyon", "érdekes"]
    b = [2,3,4]
    print("csere függvény hívása előtt: a:", a, "b:", b)
    csere(a, b)
    print("csere függvény hívása után: a:", a, "b:", b)
    

    Futtasd a fenti programot, és írd le az eredményeket. Hoppá! Nem azt tette, amit szerettünk volna! Magyarázd el miért nem. Használd a Python megjelenítőt, amely segítségével építs egy működő koncepcionális modellt! Mi lesz az a és b értéke a csere függvény hívása után?