মৌলিক

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

হালনাগাদ: · Skillaria.Top

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: শূন্য থেকে পেশাদার পর্যন্ত»-এ খরচের ট্র্যাকারের উদাহরণে বাস্তবে শেখানো হয়েছে।

সাধারণ প্রশ্ন

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-গুলো স্ট্রিং হয়ে যাবে।

ভিডিওতে বিষয়টি শিখুন

“Python 3.15: от новичка до профи” কোর্সে বিষয়টি অনুশীলনসহ বিস্তারিত শেখানো হয়েছে।

কোর্সে যান