# Kamusi katika Python (dict): kuunda, mbinu, kupitia, kupanga na frozendict

URL: https://skillaria.top/sw/guides/python/slovari-python

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:

- `frozendict` hurithi kutoka `object`, si kutoka `dict`, kwa hiyo `isinstance(cfg, dict)` itarudisha `False`. Kwa kukagua "kamusi yoyote" tumia `collections.abc.Mapping` au `isinstance(x, (dict, frozendict))`.
- Inaweza kuhashiwa tu ikiwa funguo na thamani zinaweza kuhashiwa: `frozendict(a=[1])` inaundwa, lakini `hash()` itaanguka. Kutobadilika ni cha juu juu, kama kwa tuple.
- Mpangilio unahifadhiwa, lakini `==` haiuzingatii.
- `json.dumps`, `pickle` na `copy` zinaelewa frozendict.

## Makosa ya kawaida

- **KeyError** wakati wa kusoma — tumia `get` au ukaguzi wa `in`.
- **Orodha kama ufunguo** — igeuze kuwa tuple: `d[tuple(lst)]`.
- **Kubadilisha kamusi ndani ya mzunguko** — pitia `list(d)`.
- **Kutarajia nakala kutoka kwa mgawo** — tumia `copy()` au `deepcopy`.
- **`{}` 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.

## FAQ

**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.


---
Source: Skillaria.Top (https://skillaria.top)
