অধ্যায় 3 · আসল প্রোগ্রাম লেখা
এরর ও এক্সেপশন
- পৃষ্ঠা 11 / 20
- 4 মিনিট পড়া
ভুল ঘটবেই: ফাইল পাওয়া যায় না, সংখ্যার জায়গায় ব্যবহারকারী অক্ষর লিখে দেয়, API টাইমআউট হয়, মডেল ভাঙা JSON ফেরত দেয়। Python-এ এগুলোকে বলে এক্সেপশন। কোনো এক্সেপশন সামলানো না হলে প্রোগ্রাম একটা ট্রেসব্যাক দিয়ে থেমে যায়। এগুলো ভালোভাবে সামলাতে পারাই একটা ডেমো আর মানুষের ভরসা করার মতো প্রোগ্রামের পার্থক্য।
যে এররগুলো দেখবেন
| এক্সেপশন | সাধারণ কারণ |
|---|---|
SyntaxError | কোডটা বৈধ Python নয়: কোলন, বন্ধনী বা উদ্ধৃতিচিহ্ন বাদ |
IndentationError | অসামঞ্জস্যপূর্ণ ইনডেন্টেশন |
NameError | অস্তিত্বহীন নাম ব্যবহার (প্রায়ই টাইপো) |
TypeError | ভুল টাইপের ওপর অপারেশন: "5" + 5 |
ValueError | টাইপ ঠিক, মান ভুল: int("abc") |
KeyError / IndexError | ডিকশনারিতে নেই এমন key / লিস্টে নেই এমন অবস্থান |
FileNotFoundError | নেই এমন ফাইল খোলা |
ZeroDivisionError | শূন্য দিয়ে ভাগ |
এক্সেপশন ধরা: try / except
ঝুঁকিপূর্ণ কোডটা একটা try অংশে রাখুন। মিলে যায় এমন এক্সেপশন ঘটলে Python থেমে না গিয়ে except অংশে চলে যায়:
def parse_tokens(text):
try:
return int(text)
except ValueError:
print(f"Not a number: {text!r}")
return 0
print(parse_tokens("250"))
print(parse_tokens("two hundred"))250
Not a number: 'two hundred'
0সবসময় যে নির্দিষ্ট এক্সেপশন আশা করছেন সেটাই ধরুন (এখানে ValueError)। তাহলে অন্য কোনো অপ্রত্যাশিত সমস্যা — একটা আসল বাগ — চুপচাপ হারিয়ে না গিয়ে জোরেশোরে ধরা পড়বে।
পূর্ণ রূপ: else আর finally
ল্যাঙ্গুয়েজ মডেলকে সারাক্ষণ JSON-এ উত্তর দিতে বলা হয়, আর মাঝে মাঝে সে পুরোপুরি পারে না। সেটা সুন্দরভাবে সামলানো দেখতে এমন:
import json
raw = '{"answer": "Dhaka", "confidence": 0.93' # শেষের বন্ধনীটা নেই
try:
data = json.loads(raw)
except json.JSONDecodeError as error:
print("The model did not return valid JSON:", error)
data = None
else:
print("Parsed:", data) # কোনো সমস্যা না হলেই কেবল চলে
finally:
print("Finished parsing") # সবসময় চলেThe model did not return valid JSON: Expecting ',' delimiter: line 1 column 39 (char 38)
Finished parsingexcept … as errorএক্সেপশন অবজেক্টটা দেয়; তার মেসেজ ঠিক কী আর কোথায় ভুল তা বলে।elseচলে শুধুtryঅংশ সফল হলে।finallyযা-ই হোক চলবেই — পরিষ্কারের কাজ, যেমন সংযোগ বন্ধ করার জন্য।
নিজের এক্সেপশন তোলা (raise)
আপনার ফাংশন এমন কিছু পেলে যা দিয়ে কাজ করা যায় না, স্পষ্ট মেসেজসহ একটা এক্সেপশন raise করুন। ভুল ডেটা নিয়ে এগিয়ে যাওয়ার চেয়ে শুরুতেই স্পষ্টভাবে থেমে যাওয়া অনেক ভালো:
def set_temperature(value):
if not 0 <= value <= 2:
raise ValueError(f"temperature must be between 0 and 2, got {value}")
return value
print(set_temperature(0.7))
set_temperature(5)0.7
Traceback (most recent call last):
File "main.py", line 7, in <module>
set_temperature(5)
File "main.py", line 3, in set_temperature
raise ValueError(f"temperature must be between 0 and 2, got {value}")
ValueError: temperature must be between 0 and 2, got 5একটা আসল প্যাটার্ন: এক্সপোনেনশিয়াল ব্যাকঅফসহ আবার চেষ্টা
AI API মাঝে মাঝে একটা কল ফিরিয়ে দেয়, কারণ আপনি অনেক বেশি পাঠাচ্ছেন (রেট লিমিট, HTTP 429) অথবা সার্ভিসটা ব্যস্ত। পেশাদার সমাধান হলো অপেক্ষা করে আবার চেষ্টা, প্রতিবার আরও বেশি অপেক্ষা করে — একে বলে এক্সপোনেনশিয়াল ব্যাকঅফ। Exception থেকে উত্তরাধিকার নিয়ে নিজের এক্সেপশন টাইপ বানানো যায় (উত্তরাধিকার নিয়ে পরের পাতায় আরও আছে):
import random
import time
class TemporaryAPIError(Exception):
"""এমন ব্যর্থতা, যা আবার চেষ্টা করার মতো — যেমন টাইমআউট বা রেট লিমিট।"""
random.seed(3)
def flaky_api_call():
if random.random() < 0.6:
raise TemporaryAPIError("rate limited")
return "Here is your answer."
def call_with_retries(max_attempts=5):
for attempt in range(1, max_attempts + 1):
try:
return flaky_api_call()
except TemporaryAPIError as error:
wait = 0.01 * 2 ** attempt # 0.02, 0.04, 0.08 ... সেকেন্ড
print(f"Attempt {attempt} failed ({error}); waiting {wait:.2f}s")
time.sleep(wait)
raise RuntimeError("API still failing after retries")
print(call_with_retries())Attempt 1 failed (rate limited); waiting 0.02s
Attempt 2 failed (rate limited); waiting 0.04s
Attempt 3 failed (rate limited); waiting 0.08s
Here is your answer.আসল SDK-গুলো নিজেরাই কয়েকবার আবার চেষ্টা করে (OpenAI আর Anthropic-এর SDK ডিফল্টভাবে দুবার), কিন্তু সাময়িকভাবে ব্যর্থ হতে পারে এমন অন্য যেকোনো কাজের চারপাশে এই লুপ আপনাকেই লিখতে হবে। যে এরর নিজে থেকে ঠিক হবে না, তা কখনো আবার চেষ্টা করবেন না — ভুল API key (401) প্রতিবার একইভাবে ব্যর্থ হয়।
একটা খারাপ অভ্যাস: সবকিছু ধরে ফেলা
try:
result = 10 / 0
except Exception: # খুব বেশি চওড়া: কী ভুল হলো লুকিয়ে ফেলে
result = None
print(result)Noneপ্রোগ্রামটা "চলছে", কিন্তু আপনি জানতেই পারলেন না যে সে শূন্য দিয়ে ভাগ করতে গিয়েছিল। শুধু except: বা লগ ছাড়া except Exception: বাগ লুকিয়ে ফেলে। সত্যিই সব ধরতে হলে (যেমন দীর্ঘক্ষণ চলা প্রোগ্রামের একদম ওপরে), অন্তত এররটা প্রিন্ট বা লগ করুন।
নিজে চেষ্টা করুন
- ব্যবহারকারী একটা বৈধ পূর্ণসংখ্যা না লেখা পর্যন্ত তার বয়স জিজ্ঞেস করতে থাকুন।
- ব্যবহারকারীর লেখা নামের একটা ফাইল খুলুন; না থাকলে একটা বন্ধুসুলভ মেসেজ দেখান।
safe_divide(a, b)লিখুন, যাbশূন্য হলে স্পষ্ট মেসেজসহValueErrorতোলে।