Kamusi katika Python (dict): kuunda, mbinu, kupitia, kupanga na frozendict
Kamusi (dict) katika Python ni mkusanyiko unaoweza kubadilishwa wa jozi za "ufunguo — thamani" unaopata thamani kwa ufunguo karibu papo hapo; huundwa kwa mabano ya mikunjo, kwa mfano {"kahawa": 250}, au kwa kazi dict(). Funguo ni za kipekee na lazima ziwe hashable; tangu Python 3.7 mpangilio wa kuingizwa unahifadhiwa, na katika 3.15 kuna toleo lisilobadilika lililojengwa ndani — frozendict.
Kamusi katika Python (dict) ni mkusanyiko wa jozi za "ufunguo — thamani" ambapo thamani hupatikana kwa ufunguo karibu papo hapo, hata kukiwa na rekodi nyingi kiasi gani. Ukitaka kuhesabu matumizi kwa kategoria, kuhifadhi mipangilio, au kumtafuta mtumiaji kwa id haraka, unatumia kamusi. Hapa chini ni kila kitu unachohitaji kufanya kazi na python dict: kuunda, mbinu, kupitia, kupanga, kuunganisha, na kipya cha 3.15 — frozendict.
Kamusi ni nini katika Python
Kamusi huhifadhi jozi ambapo ufunguo ni wa kipekee: ukiandika thamani kwa ufunguo ulio tayari, ya zamani inabadilishwa. Ndani ni jedwali la hashi, kwa hiyo utafutaji, kuongeza na kufuta kwa ufunguo hufanya kazi kwa wastani wa muda usiobadilika, si kwa kupitia kila kipengele.
Ufunguo lazima uwe kitu kinachoweza kuhashiwa: mfuatano, namba, tuple ya thamani zisizobadilika. Orodha haiwezi kuwa ufunguo — utapata TypeError: unhashable type: 'list'. Thamani zinaweza kuwa chochote, hata kamusi nyingine au orodha.
Tangu Python 3.7 kamusi inahakikisha kukumbuka mpangilio wa kuingizwa: ukiipitia, utapata funguo kwa mpangilio ule ulioziongeza.
Jinsi ya kuunda kamusi
Kuna njia kadhaa za kuunda kamusi, na zote hukutana katika msimbo halisi.
spent = {"Chakula": 1200, "Teksi": 450} # kiteuzi cha mabano
empty = {} # kamusi tupu
also_empty = dict() # sawa, kwa kazi dict
user = dict(name="Amina", age=30) # hoja zilizotajwa kwa jina
pairs = dict([("a", 1), ("b", 2)]) # kutoka orodha ya jozi
keys = dict.fromkeys(["x", "y"], 0) # {'x': 0, 'y': 0}
Angalia: mabano ya mikunjo matupu {} huunda kamusi tupu, si seti. Seti tupu huundwa tu kwa set().
Njia rahisi ya kujenga kamusi kutoka orodha mbili ni zip:
names = ["Chakula", "Teksi", "Sinema"]
sums = [1200, 450, 600]
spent = dict(zip(names, sums))
print(spent) # {'Chakula': 1200, 'Teksi': 450, 'Sinema': 600}
Kupata thamani kwa ufunguo: d[k] na get
Thamani husomwa kwa mabano ya mraba. Ufunguo usipokuwepo, Python itatupa KeyError. Ili kuepuka kosa, tumia mbinu get: itarudisha None au thamani chaguo-msingi.
spent = {"Chakula": 1200}
print(spent["Chakula"]) # 1200
print(spent.get("Sinema")) # None
print(spent.get("Sinema", 0)) # 0
spent["Sinema"] # KeyError: 'Sinema'
Kukagua kama ufunguo upo kwenye kamusi, tumia opereta in: "Chakula" in spent itarudisha True. Inakagua funguo, si thamani. Kwa thamani andika 1200 in spent.values().
Kuongeza, kubadilisha na kufuta
Kuongeza au kusasisha rekodi ni mstari mmoja wa mgawo. Kwa kuhesabu, mchanganyiko wa get ni rahisi sana:
spent = {}
for category, amount in [("Chakula", 250), ("Teksi", 300), ("Chakula", 400)]:
spent[category] = spent.get(category, 0) + amount
print(spent) # {'Chakula': 650, 'Teksi': 300}
Ufunguo unafutwa kwa del d[k] (itatupa KeyError ufunguo usipokuwepo) au kwa d.pop(k, default), ambayo pia inarudisha thamani. Kusafisha kamusi nzima — d.clear(). Urefu wa kamusi, yaani idadi ya jozi, ni len(d).
Mbinu za kamusi: muhtasari
| Mbinu | Inafanya nini |
|---|---|
get(k, default) | thamani ya ufunguo, au default bila kosa |
setdefault(k, default) | inarudisha thamani; ufunguo usipokuwepo kwanza inaandika default |
update(other) | inaongeza na kubadilisha jozi kutoka kamusi nyingine |
pop(k, default) | inafuta ufunguo na kurudisha thamani |
popitem() | inafuta na kurudisha jozi iliyoongezwa mwisho |
keys(), values(), items() | mionekano ya funguo, thamani na jozi |
copy() | nakala ya juu juu (shallow copy) |
clear() | kusafisha kamusi |
fromkeys(keys, value) | kamusi mpya yenye thamani moja kwa funguo zote |
setdefault: kujaza kamusi kwa orodha
Mbinu setdefault inasaidia pale thamani ni orodha na unataka kupanga kwa makundi:
groups = {}
for item, cat in [("kahawa", "Chakula"), ("daladala", "Usafiri"), ("pizza", "Chakula")]:
groups.setdefault(cat, []).append(item)
print(groups) # {'Chakula': ['kahawa', 'pizza'], 'Usafiri': ['daladala']}
update: kusasisha kamusi
update hubadilisha kamusi papo hapo: funguo mpya huongezwa, zinazolingana hubadilishwa.
cfg = {"debug": False, "lang": "sw"}
cfg.update({"debug": True, "theme": "dark"})
print(cfg) # {'debug': True, 'lang': 'sw', 'theme': 'dark'}
defaultdict: kamusi yenye thamani chaguo-msingi
collections.defaultdict ni kizazi cha dict ambacho, kinapofikiwa ufunguo usiokuwepo, chenyewe huunda thamani kwa kiwanda (factory). Msimbo wa kuhesabu na kupanga unakuwa mfupi.
from collections import defaultdict
spent = defaultdict(int)
for cat, amount in [("Chakula", 250), ("Teksi", 300), ("Chakula", 400)]:
spent[cat] += amount
print(dict(spent)) # {'Chakula': 650, 'Teksi': 300}
groups = defaultdict(list)
groups["Chakula"].append("kahawa")
Kwa kuhesabu idadi rahisi kuna pia collections.Counter: Counter(["a", "b", "a"]) itatoa Counter({'a': 2, 'b': 1}).
Kupitia kamusi: mzunguko wa for
Mzunguko wa for juu ya kamusi hupita kwenye funguo kwa chaguo-msingi. Ili kupata ufunguo na thamani pamoja, pitia items() — ndiyo njia inayotumika zaidi.
spent = {"Chakula": 650, "Teksi": 300}
for cat in spent: # funguo
print(cat)
for amount in spent.values(): # thamani
print(amount)
for cat, amount in spent.items(): # jozi
print(f"{cat}: {amount} TSh")
Huwezi kubadilisha ukubwa wa kamusi wakati unaipitia — itatokea RuntimeError: dictionary changed size during iteration. Ukihitaji kufuta baadhi ya funguo, pitia nakala: for k in list(d):.
Kuonyesha kamusi kwenye skrini
print(d) huchapisha kamusi kwenye mstari mmoja. Kwa kamusi kubwa au iliyoingiana ni rahisi zaidi kutumia moduli pprint au json.dumps(d, ensure_ascii=False, indent=2) — itaonyesha data kwa mikunjo na herufi za lugha yako bila kuzipachika kama misimbo.
Kupanga kamusi
Kamusi yenyewe haipangwi papo hapo; haina mbinu ya sort. Kupanga kamusi maana yake ni kuunda kamusi mpya kutoka jozi zilizopangwa kwa sorted.
spent = {"Teksi": 300, "Chakula": 650, "Sinema": 120}
by_key = dict(sorted(spent.items()))
print(by_key) # {'Chakula': 650, 'Sinema': 120, 'Teksi': 300}
by_value = dict(sorted(spent.items(), key=lambda p: p[1], reverse=True))
print(by_value) # {'Chakula': 650, 'Teksi': 300, 'Sinema': 120}
Ukihitaji kategoria kuu tatu tu, usirudishe matokeo kuwa kamusi: sorted(spent.items(), key=lambda p: p[1], reverse=True)[:2] itarudisha orodha ya jozi.
Kupanga orodha ya kamusi kwa sehemu fulani ni hivi: sorted(users, key=lambda u: u["age"]).
Kuunganisha na kujumlisha kamusi
Tangu Python 3.9 kamusi zinaunganishwa kwa opereta |, na |= inasasisha kamusi papo hapo. Funguo zinapolingana, operandi ya kulia ndiyo inashinda.
a = {"x": 1, "y": 2}
b = {"y": 20, "z": 3}
print(a | b) # {'x': 1, 'y': 20, 'z': 3}
print({**a, **b}) # matokeo sawa kwa kufungua
a |= b # sawa na a.update(b)
Angalia: a + b kwa kamusi haifanyi kazi, itatoa TypeError. Ukitaka kweli kujumlisha thamani za funguo zinazolingana, tumia Counter: Counter(a) + Counter(b).
Kufungua kamusi
Nyota mbili ** hufungua kamusi kuwa hoja zilizotajwa kwa jina za kazi, au kuwa kamusi nyingine:
def greet(name, city):
return f"{name} kutoka {city}"
data = {"name": "Amina", "city": "Arusha"}
print(greet(**data)) # Amina kutoka Arusha
Kizalishi cha kamusi (dict comprehension)
Kizalishi cha kamusi hujenga kamusi kwa mstari mmoja kutoka mfuatano wowote:
squares = {n: n * n for n in range(5)}
print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
big = {k: v for k, v in spent.items() if v > 200}
inverted = {v: k for k, v in {"a": 1, "b": 2}.items()}
print(inverted) # {1: 'a', 2: 'b'}
Mfano wa mwisho ni jinsi ya kugeuza kamusi kwa kubadilisha funguo na thamani mahali pake. Inafanya kazi ikiwa thamani ni za kipekee na zinaweza kuhashiwa; vinginevyo baadhi ya jozi zitapotea.
Kamusi zilizoingiana
Thamani inaweza kuwa kamusi nyingine — hivyo ndivyo miundo kama majibu ya JSON ya API au kamusi ya kamusi za watumiaji inavyoelezwa.
users = {
101: {"name": "Amina", "skills": ["python", "sql"]},
102: {"name": "Juma", "skills": ["go"]},
}
print(users[101]["skills"][0]) # python
print(users.get(103, {}).get("name")) # None, bila KeyError
Kunakili kamusi: nakala na jina la pili
Mstari b = a hainakili kamusi, bali unaweka jina la pili kwenye kitu kile kile. Ukibadilisha kupitia b, mabadiliko yataonekana pia kwenye a. Vivyo hivyo kamusi inapopitishwa kwa kazi: kazi inapokea marejeo ya kitu kilichoshirikiwa na inaweza kukiharibu kimyakimya.
import copy
a = {"limits": [0, 500]}
b = a.copy() # nakala ya juu juu
b["limits"].append(1000) # orodha ya ndani inashirikiwa!
print(a) # {'limits': [0, 500, 1000]}
c = copy.deepcopy(a) # nakala huru kabisa
Kulinganisha kamusi
Opereta == hulinganisha kamusi kwa yaliyomo: ni sawa zikiwa na jozi zote zinazofanana. Mpangilio wa funguo haujazingatiwa: {"a": 1, "b": 2} == {"b": 2, "a": 1} inatoa True. Kutafuta funguo zinazofanana, tumia shughuli za seti kwenye mionekano: a.keys() & b.keys().
Kamusi yenye aina: maelezo ya aina
Maelezo ya aina kwa kamusi huandikwa kama dict[str, int]. Ikiwa kamusi ina seti maalum ya sehemu za aina tofauti, TypedDict kutoka moduli typing inafaa:
from typing import TypedDict
class User(TypedDict):
name: str
age: int
u: User = {"name": "Amina", "age": 30}
Maelezo ya aina hayakaguliwi wakati programu inaendeshwa; yanasomwa na IDE na zana kama mypy.
Kamusi isiyobadilika: frozendict katika Python 3.15
Python 3.15 imeleta aina iliyojengwa ndani frozendict (PEP 814): hakuna haja ya kuagiza chochote, na jaribio la kuibadilisha linasababisha TypeError papo hapo. Awali kamusi isiyobadilika ilihitaji kuigwa kwa kifungashio cha moduli types au kifurushi cha nje. Hii ndiyo hasa inayohitajika kwa mipangilio ya pamoja ambayo hakuna kazi inayopaswa kuibadilisha kimyakimya.
config = frozendict(min_amount=0, max_amount=500)
config["max_amount"] = 1000
# TypeError: 'frozendict' object does not support item assignment
strict = config | {"max_amount": 300} # frozendict mpya, ya awali inabaki
cache = {config: "ripoti ya Mei"} # inaweza kuhashiwa — inafaa kuwa ufunguo
Mambo muhimu kujua, kulingana na nyenzo za kozi:
frozendicthurithi kutokaobject, si kutokadict, kwa hiyoisinstance(cfg, dict)itarudishaFalse. Kwa kukagua "kamusi yoyote" tumiacollections.abc.Mappingauisinstance(x, (dict, frozendict)).- Inaweza kuhashiwa tu ikiwa funguo na thamani zinaweza kuhashiwa:
frozendict(a=[1])inaundwa, lakinihash()itaanguka. Kutobadilika ni cha juu juu, kama kwa tuple. - Mpangilio unahifadhiwa, lakini
==haiuzingatii. json.dumps,picklenacopyzinaelewa frozendict.
Makosa ya kawaida
- KeyError wakati wa kusoma — tumia
getau ukaguzi wain. - Orodha kama ufunguo — igeuze kuwa tuple:
d[tuple(lst)]. - Kubadilisha kamusi ndani ya mzunguko — pitia
list(d). - Kutarajia nakala kutoka kwa mgawo — tumia
copy()audeepcopy. {}badala ya seti tupu — hiyo ni kamusi tupu.
Hitimisho
Dict ya Python ndiyo muundo mkuu wa data wa lugha: utafutaji wa haraka kwa ufunguo, mpangilio uliohifadhiwa wa kuingizwa, mbinu muhimu kama get, setdefault, update, kupitia items(), kupanga kwa sorted na kuunganisha kwa opereta |. Kumbuka kunakili na funguo zinazoweza kuhashiwa, na kwa mipangilio katika Python 3.15 chagua frozendict. Kamusi, orodha, tuple na seti vimefafanuliwa kwa vitendo katika kozi ya "Python 3.15: kutoka mwanzo hadi mtaalamu" kupitia mfano wa kifuatiliaji cha matumizi.
Maswali ya mara kwa mara
Je, naweza kuhifadhi aina tofauti za thamani kwenye kamusi moja?
Ndiyo, thamani zinaweza kuwa chochote na tofauti ndani ya kamusi moja: namba, mifuatano, orodha, kamusi nyingine. Kizuizi kipo kwa funguo tu — lazima ziweze kuhashiwa.
Ninawezaje kujua idadi ya vipengele vya kamusi?
Kazi len(d) inarudisha idadi ya jozi za ufunguo na thamani. Kwa kamusi tupu itarudisha 0, na kamusi tupu yenyewe katika sharti la if inachukuliwa kuwa si kweli.
dict inatofautianaje na defaultdict?
defaultdict ni kizazi cha dict ambacho, kinapofikiwa ufunguo usiokuwepo, hakitupi KeyError bali huunda thamani kwa kiwanda, kwa mfano int au list. Kwa mengine yote hufanya kazi kama kamusi ya kawaida.
Ninawezaje kupata ufunguo kwa kutumia thamani?
Hakuna mbinu ya moja kwa moja; unahitaji kupitia: next((k for k, v in d.items() if v == value), None). Ikiwa utafutaji kama huu ni wa mara kwa mara, ni bora kujenga kamusi ya kinyume kwa kizalishi {v: k for k, v in d.items()}.
Ninawezaje kuhifadhi kamusi kwenye faili?
Mara nyingi kwa moduli json: json.dump(d, f, ensure_ascii=False, indent=2) kwenye faili lililofunguliwa kwa kuandika, na json.load(f) kusoma. Funguo zitakuwa mifuatano baada ya hapo.
Mada hii inafundishwa kwa kina pamoja na mazoezi katika kozi “Python 3.15: от новичка до профи”.
Nenda kwenye kozi