Sanakirja (dict)
Sanakirja, englanniksi dictionary
ja Pythonissa lyhyesti dict
, muistuttaa rakenteeltaan fyysisen maailman sanakirjaa. Tietojenkäsittelyssä tämän termin kattokäsite on hakurakenne (associative array) ja monista kielistä löytyy jokin toteutus hajautustaulusta (hash map). Pythonissa se on dictionary. Aivan kuten paperinen sanakirja, myös Pythonin sanakirjan jokainen entiteetti sisältää kaksi entiteettiä: avaimen ja arvon.
Sanakirjan luonti
Sanakirja määritellään aaltosulkeisiin aivan kuten joukko, mutta sen sisälle tulee pilkulla erotettuna entiteettejä, jotka koostuvat puolipisteellä erotellusta avaimesta ja arvosta.
>>> {"avain": "arvo"}
{'avain': 'arvo'}
>>> dict(avain="arvo")
{'avain': 'arvo'}
>>> dict([(1, 2), (3, 4)])
{1: 2, 3: 4}
Hieman pidempi sanakirja on seuraava, joka sisältää Jukka Korpelan Pienehkön sivistyssanakirjan ensimmäiset kolme sanaa (lyhennettyjen) selitteiden kanssa.
dictionary = {
"à": "kukin, kappaleelta; vaihteluvälin ilmaisemiseen",
"a cappella": "moniäänisesti ilman säestäviä soittimia esitettävä; näin esitetty laulu tms.",
"à la": "jonkun tai jonkin mukaan, tapaan"
}
Sanakirjan luomisessa voi helpottaa Pythonin zip funktio, joka laittaa kaksi (tai enemmän) iteroitavaa muuttujaa yhteen vetoketjun lailla. Kokeile ajaa seuraava koodi esimerkiksi Jupyter Notebookissa:
keys = ["jack", "lisa", "elisa"]
values = [
["spam", "pineapple"],
["egg", "ham", "spam"],
["spam", "double spam"]
]
favorite_foods = dict(zip(keys, values))
print(favorite_foods)
Sanakirjan avaimen on oltava häshättävissä eli ajettavissa onnistuneesti Pythonin hash funktion läpi. Muista: List, Set, Dictionary eli LSD. Mikäli kokeilet ajaa koodin hash([1, 2, 3])
, Python nostaa varoituksen. Tämä tarkoittaa, että sanakirjaa ei voi myöskään käyttää sanakirjan avaimena – ja on vaikea keksiä miksi joku haluaisikaan. Sanakirja voi kuitenkin olla hyvin sanakirjan avaimen takana oleva arvo! Näin syntyy sisäikkäinen rakenne, joka on REST API:ien maailmasta tutun JSON:n kaltainen. Alla rankasti lyhennetty pseudoesimerkki sanakirjasta, joka on muotoiltu Databricks Clusters API:n palauttamasta JSON:sta.
response = {
"clusters":
[
{
"cluster_name": "my-cluster",
"spark_version": "8.2.x-scala2.12",
"aws_attributes": {
"zone_id": "us-west-2c"
},
"num_workers": 30,
"node_type_id": "i3.xlarge",
"state": "TERMINATED",
"start_time": 1618263108824,
"terminated_time": 1619746525713,
"termination_reason": {
"code": "INACTIVITY"
}
}
],
# [...], second cluster here
# [...], third cluster here
}
Warning
Muistathan, että jokaisen avaimen tulee olla uniikki (hajautusarvoltaan).
Sanakirjan käyttö
Arvojen lisääminen
Sanakirjaan voi lisätä sijoittaa avaimia asettamalla niille arvon.
Huomaa, että Python ei varoita, jos avain on jo olemassa:
Arvojen noutaminen
Huomaa, että sanakirja ei ole sekvenssi. Et voi siis viitata niihin indeksinumerolla muotoa alice[0]
.
>>> alice = {"name": "Alice", "age": 42}
>>> alice["name"]
'Alice'
# Mikäli yrität noutaa olemattoman arvon...
>>> alice["number"]
KeyError: 'number'
# Tähän löytyy get-metodi, jonka oletus on None
# tai käyttäjän määrittämä arvo
>>> alice.get("number", "N/A")
'N/A'
Arvojen muokkaus
Arvoja voi muokata sijoittamalla avaimeen uuden arvon.
>>> alice = {"name": "Alice", "age": 42}
>>> alice["age"] = alice["age"] + 1
>>> print(alice)
{'name': 'Alice', 'age': 43}
Sanakirja ja operaatiot
Aritmeettiset, vertailu ja loogiset
Aritmeettiset ja vertailuoperaattorit, poislukien ==
, eivät toimi sanakirjojen kanssa. Loogiset toimivat samalla tavalla kuin sekvenssien ja joukkojen kanssa. Loogiset peraatiot kuten and
käsittelee bool()
-funktion palauttamaa arvoa. Tyhjä sanakirja eli bool(dict())
palauttaa arvon False, ja mikä tahansa ei-tyhjä sanakirja palauttaa Truen.
Sanakirja
Aivan kuten joukolla, myös sanakirjalla on nippu omia, hyödyllisiä operaatioita tai metodeja.
Operaatio | Selite |
---|---|
list(d) | Palauttaa listan avaimista. |
len(d) | Palauttaa avainten lukumäärän |
d[key] | Palauttaa avaimen key arvon |
d.get(key) | Palauttaa avaimen key arvon (tai None) |
d[key] = value | Asettaa avaimen key arvoksi value |
del d[key] | Poistaa avaimen key ja sen arvon |
key in d | Palauttaa True, jos avain key on sanakirjassa d, muuten False |
iter(d) | Palauttaa sanakirjan avaimet iteraattorina |
d.pop(key) | Poistaa avaimen key ja palauttaa sen arvon |
d.popitem() | Poistaa ja palauttaa viimeiseksi lisätyn avaimen ja arvon |
d.reverse() | Kääntää sanakirjan avaimet |
d | other | Palauttaa yhdistetyn, uuden sanakirjan, joka sisältää d:n ja other:n |
Sanakirjan käyttö Stack:nä
Sanakirjaa voi käyttää .popitem()
:n avulla stäkkinä. Tuoreissa Pythonin versioissa (3.7+) dictionary muistaa järjestyksen, jossa entiteetit on siihen lisätty. Kokeile, mitä alla oleva koodi tulostaa. Tutki, missä järjestyksessä entiteetit tulostuvat, ja lisäksi missä tietotyypissä ne ovat.
my_stack = dict()
my_stack['a'] = 1
my_stack['b'] = 2
my_stack['c'] = 3
for _ in range(2):
print(my_stack.popitem())
my_stack['z'] = 20
my_stack['x'] = 19
my_stack['y'] = 18
while my_stack:
print(my_stack.popitem())
Moduuli: JSON
Sanakirja ja JSON ovat muodoltaan läheistä sukua toisilleen. JSON on JavaScript Object Notation, joka on JavaScriptin objektien ja sanakirjojen muotoiluun tarkoitettu notaatio. Pythonin JSON-moduuli tarjoaa kaksi funktiota, json.dumps()
ja json.loads()
, jotka muuntavat Pythonin sanakirjan JSON-muotoon ja takaisin.
import json
ingredients = [
{"id": 0, "name": "Egg", "price": 1.00},
{"id": 1, "name": "Ham", "price": 0.50},
{"id": 2, "name": "Späm", "price": 42.00},
]
# Python -> JSON
ingredients_json = json.dumps(ingredients, indent=4)
print("JSON: ", ingredients_json)
# JSON -> Python
ingredients_dict = json.loads(ingredients_json)
assert ingredients_dict == ingredients
Aja yllä oleva koodi ja tutki, kuinka Späm-sanan ääkkönen käyttäytyy JSON-merkkijonoksi materialisoituna. Kokeile myös, mitä tapahtuu, jos käytät parametriä ensure_ascii=False
json.dumps()
-funktiolle. Huomaa, että mikäli kirjoitat jälkimmäisellä tavalla JSON-tiedoston, joudut määrittämään tiedoston koodauksen, jotta ääkköset tallentuvat oikein. UTF-8 on tällöin suositus.
Harjoittele
Harjoittele JSON:sta objektiksi ja takaisin
Tallenna wikipediasta löytyvä JSON-esimerkki tiedostoon input.json
. Voit tehdä tämän vaiheen Visual Studio Codella, Pythonilla, vim:llä tai muulla valitsemallasi työkalulla. JSON kokonaisuudessaan alla:
{
"first_name": "John",
"last_name": "Smith",
"is_alive": true,
"age": 27,
"address": {
"street_address": "21 2nd Street",
"city": "New York",
"state": "NY",
"postal_code": "10021-3100"
},
"phone_numbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [
"Catherine",
"Thomas",
"Trevor"
],
"spouse": null
}
Tee sitten seuraavat:
- Lue tiedosto
input.json
ja tallenna sen sisältö muuttujaandata
. - Muunna
data
Pythonin sanakirjaksi. - Lisää John:lle uusi lapsi, esimerkiksi "Jane".
- Lisää John:lle uusi puhelinnumero, esimerkiksi "555-555-5555"
- Muunna sanakirja takaisin JSON-muotoon.
- Tallenna JSON-tiedosto
output.json
-nimellä.
Harjoittele: Pydantic Model
Tutustu Pydantic kirjastoon ja sen Model -luokkaan. Pydantic on Pythonin kirjasto, joka tarjoaa työkaluja tietotyyppien validointiin ja muuntamiseen. Se on erityisen hyödyllinen REST API:en kanssa työskennellessä. Pydanticin Model-luokka tarjoaa työkaluja Pythonin sanakirjojen muuntamiseen Pythonin luokiksi ja takaisin. Alla esimerkki kirjaston käytöstä:
from pydantic import BaseModel, Field
from enum import Enum
from typing import List
class SpeciesEnum(str, Enum):
cat = "cat"
dog = "dog"
class Pet(BaseModel):
name: str
species: SpeciesEnum
# Age field is in years and must be between 0 and 40
age_years: int = Field(gt=-1, lt=41)
class Owner(BaseModel):
name: str
pets: List[Pet]
# Define
kitty = Pet(name="Kitty", species="cat", age_years=0)
puppy = Pet(name="Puppy", species="dog", age_years=7)
lisa = Owner(name="Lisa", pets=[kitty, puppy])
# Loop
for pet in lisa.pets:
print(f"{pet.name} is a {pet.species} and is {pet.age_years} years old")
Jatka harjoitusta siten, että luet datan JSON-merkkijonon sisältävästä muuttujasta. Alla pohja:
# Täytä nämä tiedot. Voit halutessasi luoda JSON-tiedoston ja
# lukea datan sieltä.
owner_data = """
{
"name": "Unknown",
"pets": []
}
"""
# Tutustu tähän metodiin
Owner.model_validate_json(owner_data)
Tip
Huomaathan, että pydantic ei ole Pythonin sisäänrakennettu kirjasto. Sinun tulee asentaa se paketinhallinnalla (pip tai poetry).