অধ্যায় 3 · আসল প্রোগ্রাম লেখা
কম্প্রিহেনশন ও জেনারেটর
- পৃষ্ঠা 8 / 20
- 3 মিনিট পড়া
আপনি এমন লুপ লিখেছেন যা আইটেম ধরে ধরে নতুন একটা লিস্ট বানায়। প্যাটার্নটা এত সাধারণ যে Python-এ এর একটা ছোট, পড়তে সহজ রূপ আছে: কম্প্রিহেনশন। ডেটা বা AI-এর প্রায় প্রতিটা কোডে কম্প্রিহেনশন দেখবেন, তাই সাবলীলভাবে পড়তে আর লিখতে শেখা দরকার।
লিস্ট কম্প্রিহেনশন
গঠনটা হলো [expression for item in collection] — "প্রতিটা আইটেমের জন্য এটা দিয়ে একটা লিস্ট বানাও":
prices = [120, 450, 80, 990]
# লুপ দিয়ে
with_vat = []
for p in prices:
with_vat.append(p * 1.15)
# কম্প্রিহেনশন দিয়ে: একই ফলাফল, এক লাইনে
with_vat = [p * 1.15 for p in prices]
print([round(p) for p in with_vat])[138, 518, 92, 1138]if দিয়ে ছাঁকা
শেষে if condition যোগ করলে শুধু কিছু আইটেম থাকে। মডেলে পাঠানোর আগে এভাবে লেখা পরিষ্কার করা রোজকার কাজ:
reviews = ["Great!", "", "Terrible support", " ", "Loved it"]
# শুধু খালি-নয় এমন রিভিউ রাখো, পরিষ্কার করে
clean = [r.strip() for r in reviews if r.strip()]
print(clean)
lengths = [len(r) for r in clean]
print(lengths)['Great!', 'Terrible support', 'Loved it']
[6, 16, 8]জোরে পড়ুন: "reviews-এর প্রতিটা r-এর জন্য r.strip(), যদি r.strip() খালি না হয়"। পাতা ৪ মনে করুন: খালি লেখা False হিসেবে ধরা হয়।
ডিকশনারি আর সেট কম্প্রিহেনশন
দ্বিতীয় বন্ধনীর ভেতরে key: value জোড়া দিলে ডিকশনারি হয়; একটাই এক্সপ্রেশন দিলে সেট:
words = ["python", "ai", "data", "ai", "python", "ai"]
counts = {w: words.count(w) for w in set(words)}
print(dict(sorted(counts.items())))
prices_usd = {"basic": 10, "pro": 25}
prices_bdt = {plan: usd * 122 for plan, usd in prices_usd.items()}
print(prices_bdt)
lengths = {len(w) for w in words} # সেট কম্প্রিহেনশন
print(sorted(lengths)){'ai': 3, 'data': 1, 'python': 2}
{'basic': 1220, 'pro': 3050}
[2, 4, 6]জেনারেটর এক্সপ্রেশন: অলস, মেমরি-বান্ধব
কম্প্রিহেনশন প্রথম বন্ধনী দিয়ে লিখলে — অথবা সরাসরি কোনো ফাংশন কলের ভেতরে — Python পুরো লিস্টটা বানায় না। দরকার অনুযায়ী একবারে একটা করে মান তৈরি করে। দশ লাখ সংখ্যার ক্ষেত্রে এতে অনেক মেমরি বাঁচে। any() আর all()-এর সাথে এদের দারুণ মেলে:
numbers = range(1, 1_000_001)
total = sum(n * n for n in numbers) # কোনো লিস্ট তৈরিই হয় না
print(total)
scores = [0.4, 0.9, 0.7]
print(any(s > 0.8 for s in scores)) # অন্তত একটা কি 0.8-এর বেশি?
print(all(s > 0.3 for s in scores)) # সবগুলো কি 0.3-এর বেশি?333333833333500000
True
Trueনিজের জেনারেটর লেখা: yield
return-এর বদলে yield ব্যবহার করা ফাংশন হয়ে যায় জেনারেটর: প্রতিটা yield একটা মান দেয় আর পরেরটা চাওয়া পর্যন্ত থেমে থাকে। AI-এ এর একটা ক্লাসিক ব্যবহার হলো ব্যাচিং — সব ডকুমেন্ট একসাথে না পাঠিয়ে কয়েকটা কয়েকটা করে API-তে পাঠানো:
def chunks(items, size):
"""Yield successive pieces of `items`, each at most `size` long."""
for start in range(0, len(items), size):
yield items[start:start + size]
documents = [f"doc{i}" for i in range(1, 8)]
for batch in chunks(documents, 3):
print("Sending batch:", batch)Sending batch: ['doc1', 'doc2', 'doc3']
Sending batch: ['doc4', 'doc5', 'doc6']
Sending batch: ['doc7']একই ধারণা স্ট্রিমিং-এর পেছনে কাজ করে: ChatGPT যখন শব্দে শব্দে উত্তর লেখে, আপনার কোড জেনারেটরের মতো একটা স্ট্রিম থেকে টুকরোগুলো পায়। পাতা ১৮-তে এটা ব্যবহার করবেন।
কখন কম্প্রিহেনশন নয়
কম্প্রিহেনশন একটা কালেকশন বানানোর জন্য। যুক্তিতে কয়েকটা ধাপ, একটার ভেতরে আরেকটা শর্ত বা print লাগলে সাধারণ লুপই বেশি পরিষ্কার। চালাক কোডের চেয়ে পড়তে সহজ কোড ভালো।
নিজে চেষ্টা করুন
- ফাইলের নামের একটা লিস্ট থেকে শুধু
.pdfদিয়ে শেষ হওয়াগুলোর লিস্ট বানান। ["Apple", "banana", "Cherry"]-কে এমন dict-এ বদলান, যেখানে প্রতিটা শব্দের সাথে তার দৈর্ঘ্য।numbered(lines)নামে একটা জেনারেটর লিখুন, যা"1. first line","2. second line"এভাবে yield করে।