2.10. Halmazok¶
A halmaz (set) egyedi elemek rendezetlen gyűjteménye. Egy már jelen lévő érték hozzáadásának nincs hatása; az iteráció minden értéket pontosan egyszer ad vissza. A halmazok a megfelelő eszközök, amikor a tagság és a duplikációk kiszűrése számít, a sorrend viszont nem.
2.10.1. Halmaz létrehozása¶
Nem üres halmazhoz használj kapcsos zárójeleket, üreshez pedig a set() függvényt:
colours = {"red", "green", "blue"}
empty = set()
A kapcsos zárójelek úgy néznek ki, mint egy dict literál; a {} önmagában egy üres dict, nem üres halmaz – ez a Python egyik történelmi balesete. Az üres esetre használd a set() formát.
A set() bármilyen iterálható objektumból is halmazt épít, ami a szokásos módja egy sorozat duplikációinak eldobásához:
nums = [1, 2, 2, 3, 1, 4]
unique = set(nums)
print(unique)
Kimenet:
{1, 2, 3, 4}
A nyomtatási sorrend változhat – a halmazok nem ígérnek semmilyen meghatározott iterálási sorrendet.
2.10.2. Halmaz kontra szótár¶
A halmazok és a szótárak egyaránt egyedi elemeket tárolnak egy hash-táblában. A különbség az, hogy az egyes elemek mit hordoznak magukkal:
A
dictkulcs-érték párokat tárol. Egy kulcs kikeresése visszaadja az értékét.A
setcsak az elemeket tárolja. Egy elem kikeresése megmondja, hogy ott van-e.
A kettő közötti választás arról szól, hogy az egyes elemek melletti érték jelent-e bármit:
Nyúlj a halmaz felé, amikor nincs érték, ami minden elem mellé tartozik – csak az érdekel, hogy az elem jelen van-e, vagy egyedi elemekből álló csoportokat egyesítesz unióval / metszettel.
Nyúlj a szótár felé, amikor minden elem párosítva van egy adattal, amelyet a kikeresés hivatott visszaadni – egy konfigurációs leképezés, egy gyorsítótár, egy név szerint kulcsolt számláló.
A két típus sok felszíni szintaxist oszt meg, és innen ered a legtöbb félreértés. A különbségek egy blokkban:
set |
dict |
|
|---|---|---|
tartalmaz |
egyedi elemeket |
egyedi kulcsokat, mindegyikhez egy értékkel |
feltöltött literál |
|
|
üres literál |
|
|
tagság vizsgálata |
|
|
érték lekérése |
n/a |
|
elem hozzáadása |
|
|
iterálás |
elemeket ad vissza |
kulcsokat ad vissza (párokhoz használd a |
A feltöltött és az üres literál közötti aszimmetria az a buktató, amelyet érdemes kiemelni:
A kapcsos zárójelek elemekkel –
{1, 2, 3}– halmazliterált alkotnak; a kapcsos zárójelek kulcs-érték párokkal –{"a": 1}– szótárliterált. Az értelmező a benne lévők alapján különbözteti meg őket.A kapcsos zárójelek semmivel a belsejükben –
{}– üres szótárt jelentenek, nem üres halmazt. A szótárak voltak előbb; az üres literál hozzájuk tartozik. Az üres halmaznak egyáltalán nincs zárójeles literálja, ésset()formában kell leírni.
Gyakori minta, amikor egy szótárnak csak a kulcsait olvassuk valaha, hogy átváltunk halmazra – ez nyilvánvalóvá teszi a szándékot, és kivágja a felesleges értékeket a memóriából.
2.10.3. Hozzáadás és eltávolítás¶
set.add()– egy elem beszúrása.set.discard()– egy elem eltávolítása, ha jelen van, és semmittevés, ha nincs.set.remove()– egy elem eltávolítása;KeyErrorkivételt vált ki, ha hiányzik.set.clear()– a halmaz kiürítése.
s = {1, 2, 3}
s.add(4)
s.discard(99) # silent: 99 not in s
s.remove(2)
print(s)
Kimenet:
{1, 3, 4}
2.10.4. Tagság¶
Az in operátor tagságot vizsgál. Egy halmazon ez nagyjából konstans időt vesz igénybe a mérettől függetlenül – ez a fő ok, amiért egy halmazt választunk egy list helyett, ha csak azt kell megkérdezni, hogy „benne van-e ez az érték”:
if "red" in colours:
print("colour is allowed")
Egy ugyanazt a tartalmat tartalmazó list minden alkalommal az elejéről kezdene végigpásztázni, ami tíz elemnél rendben van, de tízezernél lassú.
2.10.5. Halmazműveletek¶
Két halmaz a szokásos matematikai műveletekkel kombinálható. Mindegyiknek van operátoros és metódusos formája is:
a | bvagya.union(b)– minden, ami bármelyik halmazban szerepel.a & bvagya.intersection(b)– csak az, ami mindkettőben megjelenik.a - bvagya.difference(b)– amia-ban van, deb-ben nincs.a ^ bvagya.symmetric_difference(b)– ami az egyikben van, de mindkettőben nem.
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b)
print(a & b)
print(a - b)
print(a ^ b)
Kimenet:
{1, 2, 3, 4, 5, 6}
{3, 4}
{1, 2}
{1, 2, 5, 6}
Az operátoros formák csak olvashatók; a metódusos formák bármilyen iterálható objektumot elfogadnak a jobb oldalon, nem csak egy másik halmazt (a.union([5, 6])). Válaszd azt, amelyik az adott kontextusban jobban olvasható.
2.10.6. Mi kerülhet egy halmazba¶
A halmaz elemeinek hashelhetőnek kell lenniük – ugyanaz a megkötés, mint a dict kulcsoknál. Az int, float, str, bool, bytes és tuple (ha a tartalma maga is hashelhető) mind működik. A list és a dict nem; egy ilyen hozzáadásának kísérlete TypeError kivételt vált ki.
2.10.7. frozenset¶
Egy szokásos set változtatható: az add / remove / discard minden hívása helyben módosítja az objektumot. Ez a változtathatóság kizárja, hogy hashelhető legyen, így egy halmaz nem használható dict kulcsként vagy egy másik halmaz elemeként.
A frozenset a megváltoztathatatlan megfelelője. Ugyanazokkal a kikeresésekkel és operátorokkal (in, |, &, -, ^) rendelkezik, mint a set, de nincs add / remove és nincsenek módosító metódusai. Mivel a tartalma soha nem változhat meg, egy frozenset hash-értéke jól meghatározott – így hashelhető:
primary = frozenset({"red", "green", "blue"})
secondary = frozenset({"yellow", "purple", "orange"})
palettes = {
primary: "RGB",
secondary: "mixed",
}
print(palettes[primary])
Kimenet:
RGB
Egy frozenset bármilyen iterálható objektumból építhető – frozenset() az üres esetre, frozenset(some_set) egy létező halmaz megváltoztathatatlan pillanatképének elkészítéséhez:
snapshot = frozenset(s) # immutable copy of s
s.add("new") # snapshot does not change
Két gyakori ok, amiért érdemes hozzá nyúlni:
Használat szótárkulcsként vagy halmazelemként. Bárhol, ahol egyetlen érték nem képes megragadni, amire szükséged van, ott egy
frozensetértékekből megteheti – „az ez az illesztőprogram által támogatott jellemzők halmaza”, „a profil által használt lábak halmaza”.Egy konstans lezárása. Egy megengedett nevekből álló, modulszintű
frozensetnem módosítható véletlenül egy hívó által; egy szokásossetviszont igen. Részesítsd előnyben afrozensettípust mindenhez, aminek a létrehozás után csak olvashatónak kell lennie.