# Python-এর dictionary (dict): তৈরি, মেথড, লুপ, সর্টিং ও frozendict

URL: https://skillaria.top/bn/guides/python/dicts-python

Python-এর dict হলো পরিবর্তনযোগ্য «key — value» জোড়ার কালেকশন, যেখানে key দিয়ে মান প্রায় তাৎক্ষণিক পাওয়া যায়; তৈরি হয় কোঁকড়া বন্ধনীতে, যেমন {"coffee": 250}, অথবা dict() ফাংশনে। Key অনন্য ও হ্যাশযোগ্য হতে হয়, Python 3.7 থেকে সন্নিবেশের ক্রম ধরে রাখে, আর Python 3.15-এ যুক্ত হয়েছে অন্তর্নির্মিত অপরিবর্তনীয় frozendict।

Python-এর dictionary (`dict`) হলো «key — value» জোড়ার একটি কালেকশন, যেখানে key দিয়ে মান খুঁজে পাওয়া যায় প্রায় তাৎক্ষণিকভাবে, রেকর্ড যতই থাকুক না কেন। ক্যাটাগরি অনুযায়ী খরচ জমাতে, সেটিংস রাখতে বা id দিয়ে ব্যবহারকারী খুঁজতে আপনি dictionary-ই ব্যবহার করবেন। নিচে python dict-এর সব প্রয়োজনীয় দিক: তৈরি, মেথড, লুপ, সর্টিং, মার্জ এবং Python 3.15-এর নতুন `frozendict`।

## Python-এর dictionary কী

Dictionary জোড়া রাখে, যেখানে key অনন্য: বিদ্যমান key-তে নতুন মান লিখলে পুরনোটি বদলে যায়। ভেতরে এটি একটি হ্যাশ টেবিল, তাই key দিয়ে খোঁজা, যোগ ও মোছা গড়ে সমান সময়ে হয়, তালিকা ধরে ধরে যেতে হয় না।

Key হতে পারে শুধু হ্যাশযোগ্য অবজেক্ট: স্ট্রিং, সংখ্যা, অপরিবর্তনীয় মানের tuple। তালিকা key হতে পারে না — পাবেন `TypeError: unhashable type: 'list'`। মান কিন্তু যেকোনো কিছু হতে পারে, এমনকি অন্য dictionary বা তালিকাও।

Python 3.7 থেকে dictionary সন্নিবেশের ক্রম নিশ্চিতভাবে মনে রাখে: লুপ চালালে key-গুলো যে ক্রমে যোগ করা হয়েছিল, সেভাবেই আসে।

## Dictionary তৈরির উপায়

Dictionary তৈরির কয়েকটি উপায় আছে, সবই বাস্তব কোডে দেখা যায়।

```
spent = {"Food": 1200, "Taxi": 450}       # লিটারাল
empty = {}                                 # খালি dictionary
also_empty = dict()                        # একই কাজ dict ফাংশন দিয়ে
user = dict(name="Anika", age=30)          # নামযুক্ত আর্গুমেন্ট
pairs = dict([("a", 1), ("b", 2)])         # জোড়ার তালিকা থেকে
keys = dict.fromkeys(["x", "y"], 0)        # {'x': 0, 'y': 0}
```

মনে রাখবেন: খালি কোঁকড়া বন্ধনী `{}` খালি dictionary বানায়, set নয়। খালি set বানাতে লাগে `set()`।

দুটি তালিকা থেকে dictionary বানানোর সুবিধাজনক উপায় `zip`:

```
names = ["Food", "Taxi", "Cinema"]
sums = [1200, 450, 600]
spent = dict(zip(names, sums))
print(spent)   # {'Food': 1200, 'Taxi': 450, 'Cinema': 600}
```

## key দিয়ে প্রবেশ: d[k] ও get

মান পড়া হয় বর্গাকার বন্ধনী দিয়ে। Key না থাকলে Python `KeyError` ছোঁড়ে। ত্রুটি এড়াতে `get` মেথড ব্যবহার করুন: এটি `None` বা দেওয়া ডিফল্ট মান ফেরত দেয়।

```
spent = {"Food": 1200}
print(spent["Food"])            # 1200
print(spent.get("Cinema"))      # None
print(spent.get("Cinema", 0))   # 0
spent["Cinema"]                 # KeyError: 'Cinema'
```

Key আছে কি না, যাচাই করতে `in` অপারেটর: `"Food" in spent` দেবে `True`। এটি শুধু key যাচাই করে, মান নয়। মানের জন্য লিখুন `1200 in spent.values()`।

## যোগ, বদল ও মোছা

কোনো রেকর্ড যোগ বা হালনাগাদ করা এক লাইনের অ্যাসাইনমেন্ট। গণনার জন্য `get`-এর সঙ্গে জুটি খুব কাজের:

```
spent = {}
for category, amount in [("Food", 250), ("Taxi", 300), ("Food", 400)]:
    spent[category] = spent.get(category, 0) + amount
print(spent)   # {'Food': 650, 'Taxi': 300}
```

Key মুছতে `del d[k]` (key না থাকলে `KeyError`) অথবা `d.pop(k, default)` ব্যবহার করুন, যেটি মানও ফেরত দেয়। পুরো dictionary খালি করতে `d.clear()`। দৈর্ঘ্য, অর্থাৎ জোড়ার সংখ্যা, পাওয়া যায় `len(d)` দিয়ে।

## Dictionary-র মেথড: এক নজরে

| মেথড | কাজ |
| --- | --- |

| `get(k, default)` | key-র মান, না থাকলে ত্রুটি ছাড়া default |

| `setdefault(k, default)` | মান ফেরত দেয়; key না থাকলে আগে default লেখে |

| `update(other)` | অন্য dictionary-র জোড়া যোগ ও বদল করে |

| `pop(k, default)` | key মুছে মান ফেরত দেয় |

| `popitem()` | সর্বশেষ যোগ করা জোড়াটি মুছে ফেরত দেয় |

| `keys()`, `values()`, `items()` | key, মান ও জোড়ার দৃশ্য |

| `copy()` | অগভীর কপি |

| `clear()` | dictionary খালি করা |

| `fromkeys(keys, value)` | একই মানসহ নতুন dictionary |

### setdefault: তালিকা দিয়ে গ্রুপ করা

মান যখন তালিকা হয় এবং গ্রুপ করতে হয়, `setdefault` কাজে আসে:

```
groups = {}
for item, cat in [("coffee", "Food"), ("bus", "Transport"), ("pizza", "Food")]:
    groups.setdefault(cat, []).append(item)
print(groups)   # {'Food': ['coffee', 'pizza'], 'Transport': ['bus']}
```

### update: dictionary হালনাগাদ

`update` dictionary-কে নিজের জায়গাতেই বদলায়: নতুন key যোগ হয়, মিলে যাওয়া key-র মান লেখা হয়।

```
cfg = {"debug": False, "lang": "bn"}
cfg.update({"debug": True, "theme": "dark"})
print(cfg)   # {'debug': True, 'lang': 'bn', 'theme': 'dark'}
```

## defaultdict: ডিফল্ট মানসহ dictionary

`collections.defaultdict` হলো dict-এর একটি উপশ্রেণি, যা না থাকা key-তে গেলে ফ্যাক্টরি দিয়ে নিজেই মান বানিয়ে নেয়। গণনা ও গ্রুপ করার কোড তাই ছোট হয়।

```
from collections import defaultdict

spent = defaultdict(int)
for cat, amount in [("Food", 250), ("Taxi", 300), ("Food", 400)]:
    spent[cat] += amount
print(dict(spent))   # {'Food': 650, 'Taxi': 300}

groups = defaultdict(list)
groups["Food"].append("coffee")
```

শুধু সংখ্যা গোনার জন্য আছে `collections.Counter`: `Counter(["a", "b", "a"])` দেয় `Counter({'a': 2, 'b': 1})`।

## Dictionary-তে লুপ: for

লুপে `for` ডিফল্টভাবে key ধরে চলে। key ও মান একসঙ্গে পেতে `items()`-এর উপর লুপ চালান — এটিই সবচেয়ে সাধারণ ব্যবহার।

```
spent = {"Food": 650, "Taxi": 300}

for cat in spent:                    # key-গুলো
    print(cat)

for amount in spent.values():        # মানগুলো
    print(amount)

for cat, amount in spent.items():    # জোড়াগুলো
    print(f"{cat}: {amount} ৳")
```

লুপ চলার সময় dictionary-র আকার বদলানো যায় না — পাবেন `RuntimeError: dictionary changed size during iteration`। কিছু key মুছতে হলে অনুলিপির উপর লুপ চালান: `for k in list(d):`।

## Dictionary ছাপানো

`print(d)` dictionary-কে এক লাইনে ছাপায়। বড় বা নেস্টেড dictionary-র জন্য `pprint` মডিউল বা `json.dumps(d, ensure_ascii=False, indent=2)` ভালো — এতে ডেটা ইন্ডেন্টসহ এবং বাংলা অক্ষর escape ছাড়া দেখা যায়।

## Dictionary সাজানো

Dictionary নিজের জায়গায় সাজানো যায় না, তার `sort` মেথড নেই। Dictionary সাজানো মানে `sorted` দিয়ে সাজানো জোড়া থেকে একটি নতুন dictionary বানানো।

```
spent = {"Taxi": 300, "Food": 650, "Cinema": 120}

by_key = dict(sorted(spent.items()))
print(by_key)    # {'Cinema': 120, 'Food': 650, 'Taxi': 300}

by_value = dict(sorted(spent.items(), key=lambda p: p[1], reverse=True))
print(by_value)  # {'Food': 650, 'Taxi': 300, 'Cinema': 120}
```

শুধু শীর্ষ N ক্যাটাগরি দরকার হলে ফলটি আবার dictionary বানাবেন না: `sorted(spent.items(), key=lambda p: p[1], reverse=True)[:2]` জোড়ার একটি তালিকা দেবে।

Dictionary-র তালিকা একটি ফিল্ড অনুযায়ী সাজাতে: `sorted(users, key=lambda u: u["age"])`।

## Dictionary মার্জ ও যোগ

Python 3.9 থেকে dictionary মেশানো যায় `|` অপারেটরে, আর `|=` নিজের জায়গায় হালনাগাদ করে। Key মিললে ডান দিকের মানটি জেতে।

```
a = {"x": 1, "y": 2}
b = {"y": 20, "z": 3}
print(a | b)          # {'x': 1, 'y': 20, 'z': 3}
print({**a, **b})     # একই ফল আনপ্যাক দিয়ে
a |= b                # a.update(b)-এর মতো
```

মনে রাখবেন: dictionary-তে `a + b` কাজ করে না, হবে `TypeError`। একই key-র মানগুলো যদি যোগ করতে চান, `Counter` ব্যবহার করুন: `Counter(a) + Counter(b)`।

### Dictionary আনপ্যাক

দুটি তারকাচিহ্ন `**` dictionary-কে ফাংশনের নামযুক্ত আর্গুমেন্টে বা অন্য dictionary-তে ছড়িয়ে দেয়:

```
def greet(name, city):
    return f"{name} from {city}"

data = {"name": "Anika", "city": "Dhaka"}
print(greet(**data))   # Anika from Dhaka
```

## Dictionary comprehension

Dictionary comprehension যেকোনো ক্রম থেকে এক লাইনে dictionary বানায়:

```
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'}
```

শেষ উদাহরণটি dictionary উল্টে দেওয়ার উপায় — key ও মান জায়গা বদলায়। কাজ করে যদি মানগুলো অনন্য ও হ্যাশযোগ্য হয়, নইলে কিছু জোড়া হারিয়ে যাবে।

## নেস্টেড dictionary

মান হিসেবে আরেকটি dictionary থাকতে পারে — এভাবেই API-র JSON উত্তর বা ব্যবহারকারীদের «dictionary of dictionaries» বর্ণনা করা হয়।

```
users = {
    101: {"name": "Anika", "skills": ["python", "sql"]},
    102: {"name": "Karim", "skills": ["go"]},
}
print(users[101]["skills"][0])            # python
print(users.get(103, {}).get("name"))     # None, KeyError ছাড়াই
```

## Dictionary কপি করা: কপি বনাম দ্বিতীয় নাম

`b = a` dictionary কপি করে না, একই অবজেক্টে দ্বিতীয় নাম দেয়। `b` দিয়ে বদলালে `a`-তেও দেখা যাবে। ফাংশনে dictionary পাঠালেও একই ঘটে: ফাংশন একই অবজেক্টের রেফারেন্স পায় এবং নীরবে সেটি নষ্ট করতে পারে।

```
import copy

a = {"limits": [0, 500]}
b = a.copy()              # অগভীর কপি
b["limits"].append(1000)  # ভেতরের তালিকা ভাগাভাগি!
print(a)                  # {'limits': [0, 500, 1000]}

c = copy.deepcopy(a)      # সম্পূর্ণ স্বাধীন কপি
```

## Dictionary তুলনা

`==` অপারেটর dictionary-কে বিষয়বস্তু অনুযায়ী তুলনা করে: সব জোড়া মিললে সমান। Key-র ক্রম এখানে বিবেচ্য নয়: `{"a": 1, "b": 2} == {"b": 2, "a": 1}` দেবে `True`। মিল key খুঁজতে দৃশ্যগুলোর উপর set-অপারেশন চালান: `a.keys() & b.keys()`।

## টাইপ-নির্দেশ: annotation

Dictionary-র annotation লেখা হয় `dict[str, int]` আকারে। নির্দিষ্ট ফিল্ড ও বিভিন্ন ধরনের মানের জন্য `typing` মডিউলের `TypedDict` সুবিধাজনক:

```
from typing import TypedDict

class User(TypedDict):
    name: str
    age: int

u: User = {"name": "Anika", "age": 30}
```

Annotation চলার সময় যাচাই হয় না; এগুলো পড়ে IDE ও mypy-র মতো বিশ্লেষক।

## অপরিবর্তনীয় dictionary: Python 3.15-এর frozendict

Python 3.15-এ এসেছে অন্তর্নির্মিত `frozendict` ধরন (PEP 814): আলাদাভাবে আমদানি লাগে না, আর বদলানোর চেষ্টা সঙ্গে সঙ্গে `TypeError` দেয়। আগে অপরিবর্তনীয় dictionary বানাতে `types` মডিউলের র‍্যাপার বা তৃতীয় পক্ষের প্যাকেজ লাগত। সাধারণ সেটিংস, যা কোনো ফাংশন নীরবে বদলাতে পারবে না, তার জন্য এটিই দরকার।

```
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, মূলটি অক্ষত
cache = {config: "May report"}          # হ্যাশযোগ্য — key হিসেবে ব্যবহারযোগ্য
```

কোর্সের উপকরণ অনুযায়ী যা জানা জরুরি:

- `frozendict` `object`-এর উত্তরাধিকারী, `dict`-এর নয়; তাই `isinstance(cfg, dict)` দেয় `False`। «যেকোনো dictionary» যাচাই করতে `collections.abc.Mapping` বা `isinstance(x, (dict, frozendict))` ব্যবহার করুন।
- এটি হ্যাশযোগ্য শুধু তখনই, যখন key ও মানগুলো হ্যাশযোগ্য: `frozendict(a=[1])` তৈরি হয়, কিন্তু `hash()` ব্যর্থ হয়। অপরিবর্তনীয়তা অগভীর, tuple-এর মতো।
- ক্রম সংরক্ষিত থাকে, কিন্তু `==` তা বিবেচনায় নেয় না।
- `json.dumps`, `pickle` ও `copy` frozendict বোঝে।

## সাধারণ ভুল

- **পড়ার সময় KeyError** — `get` ব্যবহার করুন বা `in` দিয়ে যাচাই করুন।
- **key হিসেবে তালিকা** — তালিকাকে tuple বানান: `d[tuple(lst)]`।
- **লুপের মধ্যে dictionary বদলানো** — `list(d)`-এর উপর লুপ চালান।
- **অ্যাসাইনমেন্ট থেকে কপির আশা** — `copy()` বা `deepcopy` করুন।
- **`{}` দিয়ে খালি set** — এটি খালি dictionary।

## সারসংক্ষেপ

Python-এর dict হলো ভাষার প্রধান ডেটা কাঠামো: key দিয়ে দ্রুত খোঁজা, সন্নিবেশের ক্রম ধরে রাখা, `get`, `setdefault`, `update`-এর মতো সুবিধাজনক মেথড, `items()` দিয়ে লুপ, `sorted` দিয়ে সাজানো এবং `|` দিয়ে মার্জ। কপি ও হ্যাশযোগ্য key-এর ব্যাপারে সতর্ক থাকুন, আর Python 3.15-এ সেটিংসের জন্য `frozendict` নিন। Dictionary, তালিকা, tuple ও set কোর্সের «Python 3.15: শূন্য থেকে পেশাদার পর্যন্ত»-এ খরচের ট্র্যাকারের উদাহরণে বাস্তবে শেখানো হয়েছে।

## FAQ

**Dictionary-তে কি বিভিন্ন ধরনের মান রাখা যায়?**

হ্যাঁ, মানগুলো একই dictionary-তে আলাদা ধরনের হতে পারে: সংখ্যা, স্ট্রিং, তালিকা, অন্য dictionary। শুধু key-র ক্ষেত্রে শর্ত আছে — সেগুলো হ্যাশযোগ্য হতে হবে।

**Dictionary-তে কয়টি উপাদান আছে কীভাবে জানব?**

len(d) ফাংশন জোড়ার সংখ্যা দেয়। খালি dictionary-র জন্য ফল 0, আর if-এর শর্তে খালি dictionary মিথ্যা হিসেবে গণ্য হয়।

**dict ও defaultdict-এর পার্থক্য কী?**

defaultdict হলো dict-এর উপশ্রেণি, যা না থাকা key-তে গেলে KeyError না দিয়ে int বা list-এর মতো ফ্যাক্টরি দিয়ে মান বানায়। বাকি আচরণ সাধারণ dictionary-র মতোই।

**মান দিয়ে key কীভাবে খুঁজব?**

সরাসরি মেথড নেই, লুপ দিয়ে খুঁজতে হয়: next((k for k, v in d.items() if v == value), None)। ঘন ঘন দরকার হলে উল্টানো dictionary বানান: {v: k for k, v in d.items()}।

**dictionary ফাইলে কীভাবে সংরক্ষণ করব?**

সাধারণত json মডিউল দিয়ে: লেখার জন্য খোলা ফাইলে json.dump(d, f, ensure_ascii=False, indent=2), আর পড়তে json.load(f)। এতে key-গুলো স্ট্রিং হয়ে যাবে।


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