2.10. Joukot¶
Joukko on järjestämätön kokoelma yksilöllisiä alkioita. Jo olemassa olevan arvon lisäämisellä ei ole vaikutusta; iterointi tuottaa kunkin arvon täsmälleen kerran. Joukot ovat oikea työkalu, kun kuuluvuus ja kaksoiskappaleiden poisto ovat tärkeitä eikä järjestyksellä ole väliä.
2.10.1. Joukon luominen¶
Käytä aaltosulkeita ei-tyhjälle joukolle tai set() tyhjälle:
colours = {"red", "green", "blue"}
empty = set()
Aaltosulkeet näyttävät dict -literaalilta; pelkkä {} on tyhjä sanakirja, ei tyhjä joukko – yksi Pythonin historiallisista vahingoista. Käytä set() tyhjässä tapauksessa.
set() rakentaa myös joukon mistä tahansa iteroitavasta, mikä on tavallinen tapa pudottaa kaksoiskappaleet jonosta:
nums = [1, 2, 2, 3, 1, 4]
unique = set(nums)
print(unique)
Tuloste:
{1, 2, 3, 4}
Tulostusjärjestys voi vaihdella – joukot eivät lupaa iteroida missään tietyssä järjestyksessä.
2.10.2. Joukko vs. sanakirja¶
Sekä joukot että sanakirjat tallentavat yksilöllisiä alkioita hajautustauluun. Ero on siinä, mitä kukin alkio kantaa mukanaan:
dicttallentaa avain-arvo-pareja. Avaimen haku palauttaa sen arvon.settallentaa pelkät alkiot. Alkion haku kertoo, onko se siellä.
Valinta näiden kahden välillä koskee sitä, tarkoittaako kunkin alkion vieressä oleva arvo mitään:
Valitse joukko, kun mikään arvo ei kuulu kunkin alkion viereen – välität vain siitä, onko alkio mukana, tai yhdistät ryhmiä yksilöllisiä alkioita unionilla / leikkauksella.
Valitse sanakirja, kun kukin alkio on pariutettu datan kanssa, jonka haku on tarkoitettu noutamaan – konfiguraatiokuvaus, välimuisti tai nimellä avaintettu laskuri.
Nämä kaksi tyyppiä jakavat paljon pintasyntaksia, mistä suurin osa sekaannuksesta johtuu. Erot yhdessä lohkossa:
joukko |
sanakirja |
|
|---|---|---|
sisältää |
yksilöllisiä alkioita |
yksilöllisiä avaimia, kullakin arvo |
täytetty literaali |
|
|
tyhjä literaali |
|
|
kuuluvuustesti |
|
|
arvon haku |
ei käytössä |
|
alkion lisäys |
|
|
iterointi |
tuottaa alkiot |
tuottaa avaimet (käytä |
Epäsymmetria täytetyn ja tyhjän literaalin välillä on sudenkuoppa, joka kannattaa nostaa esiin:
Aaltosulkeet, joissa on alkioita sisällä –
{1, 2, 3}– ovat joukkoliteraali; aaltosulkeet, joissa on avain-arvo-pareja –{"a": 1}– ovat sanakirjaliteraali. Jäsennin erottaa ne sen perusteella, mitä sisällä on.Aaltosulkeet, joissa ei ole mitään sisällä –
{}– ovat tyhjä sanakirja, ei tyhjä joukko. Sanakirjat tulivat ensin; tyhjä literaali kuuluu niille. Tyhjällä joukolla ei ole lainkaan aaltosulkeliteraalia, ja se on kirjoitettava muodossaset().
Yleinen kuvio silloin, kun sanakirjasta luetaan koskaan vain avaimet, on vaihtaa joukkoon – se tekee tarkoituksen ilmeiseksi ja karsii käyttämättömät arvot pois muistista.
2.10.3. Lisääminen ja poistaminen¶
set.add()– lisää yhden alkion.set.discard()– poistaa alkion, jos se on mukana, eikä tee mitään, jos ei.set.remove()– poistaa alkion; nostaaKeyError-poikkeuksen, jos se puuttuu.set.clear()– tyhjentää joukon.
s = {1, 2, 3}
s.add(4)
s.discard(99) # silent: 99 not in s
s.remove(2)
print(s)
Tuloste:
{1, 3, 4}
2.10.4. Kuuluvuus¶
Operaattori in testaa kuuluvuutta. Joukolla se on suunnilleen vakioaikainen koosta riippumatta – mikä on pääasiallinen syy valita joukko list -tyypin sijaan, kun haluat vain kysyä ”onko tämä arvo siellä”:
if "red" in colours:
print("colour is allowed")
list, jolla on sama sisältö, kävisi läpi alusta joka kerta, mikä on hyvä kymmenelle alkiolle mutta hidas kymmenelletuhannelle.
2.10.5. Joukko-operaatiot¶
Kaksi joukkoa voidaan yhdistää tavanomaisilla matemaattisilla operaatioilla. Jokaisella on sekä operaattorimuoto että metodimuoto:
a | btaia.union(b)– kaikki kummassa tahansa joukossa.a & btaia.intersection(b)– vain se, mikä esiintyy molemmissa.a - btaia.difference(b)–a:ssa mutta eib:ssä.a ^ btaia.symmetric_difference(b)– yhdessä mutta ei molemmissa.
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b)
print(a & b)
print(a - b)
print(a ^ b)
Tuloste:
{1, 2, 3, 4, 5, 6}
{3, 4}
{1, 2}
{1, 2, 5, 6}
Operaattorimuodot ovat vain luettavissa; metodimuodot hyväksyvät oikealla puolella minkä tahansa iteroitavan, ei vain toista joukkoa (a.union([5, 6])). Valitse se, joka lukeutuu paremmin asiayhteydessä.
2.10.6. Mikä voi mennä joukkoon¶
Joukon alkioiden on oltava hajautettavia – sama rajoitus kuin dict -avaimilla. int, float, str, bool, bytes ja tuple (kun sen sisältö on itse hajautettavaa) toimivat kaikki. list ja dict eivät; sellaisen lisäämisen yrittäminen nostaa TypeError -poikkeuksen.
2.10.7. frozenset¶
Tavallinen set on muuttuva: jokainen kutsu add / remove / discard muuttaa oliota paikan päällä. Tuo muuttuvuus estää sitä olemasta hajautettava, joten joukkoa ei voi käyttää dict -avaimena eikä toisen joukon jäsenenä.
frozenset on muuttumaton vastine. Sillä on samat haut ja operaattorit (in, |, &, -, ^) kuin set -tyypillä, mutta ei add / remove -metodeja eikä mitään muuttavia metodeja. Koska mikään ei voi koskaan muuttaa sen sisältöä, frozenset -olion hajautusarvo on hyvin määritelty – joten se on hajautettava:
primary = frozenset({"red", "green", "blue"})
secondary = frozenset({"yellow", "purple", "orange"})
palettes = {
primary: "RGB",
secondary: "mixed",
}
print(palettes[primary])
Tuloste:
RGB
Rakenna frozenset mistä tahansa iteroitavasta – frozenset() tyhjälle tapaukselle, frozenset(some_set) muuttumattoman tilannekuvan ottamiseksi olemassa olevasta joukosta:
snapshot = frozenset(s) # immutable copy of s
s.add("new") # snapshot does not change
Kaksi yleistä syytä turvautua siihen:
Käyttö sanakirjan avaimena tai joukon jäsenenä. Aina kun yksittäinen arvo ei voi tallentaa tarvitsemaasi,
frozensetarvoja voi – ”tämän ajurin tukemien piirteiden joukko”, ”tämän profiilin käyttämien nastojen joukko”.Lukitse vakio. Moduulitason
frozensetsallituista nimistä ei voi vahingossa muuttua kutsujan toimesta; tavallinensetvoi. Suosifrozenset-tyyppiä kaikelle, jonka on tarkoitus olla vain luettavissa luonnin jälkeen.