ফাংশন — একটি সিদ্ধান্ত, একটি নাম
def দিয়ে ফাংশন লেখা, return আর print-এর পার্থক্য, শুরুতেই গার্ড দিয়ে প্রান্ত সামলানো, আর ডকস্ট্রিং।
- 1সমস্যা
- 2বোঝা
- 3উদাহরণ
- 4অনুমান
- 5নিজে করা
- 6কঠিন করা
যে সমস্যাটা আমরা সমাধান করছি
দুটি দলের গড় নম্বর বের করতে হবে:
marks_a = [72, 45]
marks_b = [90, 33, 61]
print(round(sum(marks_a) / len(marks_a), 2))
print(round(sum(marks_b) / len(marks_b), 2))58.5
61.33দুটি লাইন প্রায় একই, কেবল নামটা আলাদা। তৃতীয় দল এলে তৃতীয় লাইন, চতুর্থ দলে চতুর্থ।
সমস্যাটা লেখার পরিশ্রম নয় — কপি করা সস্তা। সমস্যাটা হলো একই সিদ্ধান্ত এখন কয়েক জায়গায় লেখা আছে। গড়কে দুই ঘরের বদলে এক ঘরে দেখাতে বললে প্রতিটি লাইন খুঁজে বদলাতে হবে, আর একটি বাদ পড়লে প্রোগ্রামটি দুই জায়গায় দুই রকম আচরণ করবে — কোনো ত্রুটি ছাড়াই।
আর একটি খালি লিস্ট এলে? sum([]) / len([]) মানে শূন্য দিয়ে ভাগ, আর প্রোগ্রাম থেমে যায়। সেই পরীক্ষাটা প্রতিটি লাইনে আলাদা করে বসাতে হবে।
ফাংশন হলো একটি সিদ্ধান্তকে একবার লিখে একটি নাম দেওয়া। এরপর সেই নামটা ডাকলেই কাজ হয়, আর বদলাতে হলে একটিমাত্র জায়গা।
এই অধ্যায় শেষে আপনি পারবেন
defদিয়ে ফাংশন লিখতে আর ডাকতেreturnআরprint-এর পার্থক্য বলতে — এই অধ্যায়ের সবচেয়ে জরুরি জিনিস- একটি ফাংশনকে ছোট আর একটি কাজেই সীমিত রাখতে
- প্রান্তিক অবস্থা সামলাতে শুরুতেই একটি গার্ড লিখতে
- ডকস্ট্রিং লিখতে
আগে যা জানা লাগবে: কম্প্রিহেনশন।
প্রথম ফাংশন
def average(values):
return round(sum(values) / len(values), 2)
print(average([72, 45]))
print(average([90, 33, 61]))58.5
61.33গঠনটা:
def— «আমি একটি ফাংশন তৈরি করছি»average— নাম, যে নিয়মে ভেরিয়েবলের নাম দেন সেই নিয়মেই(values)— প্যারামিটার, অর্থাৎ ভেতরে ডেটা আসার দরজা:আর ইন্ডেন্ট করা ব্লক — শরীর, ঠিকifবাfor-এর মতোreturn— ফল ফেরত পাঠানো
average([72, 45]) লেখাকে বলে কল করা। [72, 45] হলো আর্গুমেন্ট — যা সত্যিই পাঠানো হচ্ছে; values হলো প্যারামিটার — ভেতরের নাম। দুটো আলাদা শব্দ, আর ত্রুটির বার্তায় দুটোই আসে, তাই পার্থক্যটা মনে রাখা কাজে দেয়।
দুটি খালি লাইন। ফাংশনের সংজ্ঞার পর দুটি খালি লাইন রাখা পাইথনের প্রচলিত রীতি। পাইথন এক লাইনেও চলে, কিন্তু সব পাইথন কোড এভাবে লেখা, তাই অভ্যাস করে নেওয়াই ভালো।
return আর print — এক নয়
এটি এই অধ্যায়ের সবচেয়ে গুরুত্বপূর্ণ অংশ, আর নতুনদের সবচেয়ে বড় বিভ্রান্তি।
def with_return(x):
return x * 2
def with_print(x):
print(x * 2)
a = with_return(5)
b = with_print(5)
print(a)
print(b)
print(a + 1)10
10
None
11পর্দায় প্রথম দুটি 10 দেখে মনে হয় ফাংশন দুটি একই। তা নয়।
with_return মানটি ফেরত দিয়েছে, তাই a-তে 10 ধরা আছে, আর তার সাথে যোগ করা যাচ্ছে — শেষ লাইনে 11।
with_print মানটি দেখিয়েছে এবং কিছু ফেরত দেয়নি, তাই b হলো None। পর্দায় সংখ্যাটা দেখা গেছে ঠিকই, কিন্তু প্রোগ্রামের হাতে কিছু আসেনি। b + 1 লিখলে TypeError হতো।
নিয়মটি এভাবে মনে রাখুন: print মানুষের জন্য, return প্রোগ্রামের জন্য। হিসাব করার ফাংশন return করবে; দেখানোর কাজটা ডাকা জায়গায় হবে। এতে একই ফাংশন একবার পর্দায় ছাপার কাজে, আরেকবার ফাইলে লেখার কাজে ব্যবহার করা যায়।
return না লিখলে ফাংশন নীরবে None ফেরত দেয় — এটিই append আর .sort()-এর সেই None, যা দ্বাদশ ও ত্রয়োদশ অধ্যায়ে ভুগিয়েছিল। এখন বোঝা যায় ওরা কেন None দিত: ওদের কাজ ছিল কিছু বদলানো, কিছু ফেরত দেওয়া নয়।
return সাথে সাথে থামিয়ে দেয়
def check(mark):
if mark >= 40:
return "pass"
return "fail"
print(check(72))
print(check(20))pass
failreturn চলা মাত্র ফাংশন শেষ — বাকি লাইনগুলো আর চলে না। তাই এখানে else লাগেনি: প্রথম return চললে দ্বিতীয় লাইনে পৌঁছানোই যায় না।
এই ধরনটি — শর্ত মিললে সাথে সাথে return — নবম অধ্যায়ের গভীর if/else গাছগুলোকে সমতল করে দেয়, আর কোড পড়া অনেক সহজ হয়।
প্রান্ত সামলানো — গার্ড
এই অধ্যায়ের শুরুর সমস্যাটা মনে আছে? খালি লিস্ট:
def average(values):
return sum(values) / len(values)
print(average([]))ZeroDivisionError: division by zeroসমাধানটি ফাংশনের একেবারে শুরুতে বসে:
def average(values):
if not values:
return 0.0
return round(sum(values) / len(values), 2)
print(average([72, 45]))
print(average([]))58.5
0.0if not values — অষ্টম অধ্যায়ের সত্যতার নিয়ম আবার: খালি লিস্ট মিথ্যা, তাই not সেটিকে সত্য করে। len(values) == 0 লেখার দরকার নেই।
একেই বলে গার্ড: অস্বাভাবিক অবস্থাটা শুরুতেই সামলে নাও, তারপর বাকি কোডটা নির্দ্বিধায় লেখো। ফাংশন এই কাজটা সহজ করে দেয় — পরীক্ষাটা একবার লেখা হলো, আর সব কলার তার সুবিধা পেল।
0.0কি ঠিক উত্তর? আলোচনার বিষয়। শূন্যটি «কারও নম্বর নেই» আর «সবাই শূন্য পেয়েছে» — দুটোকে এক করে ফেলে। বাস্তব প্রোগ্রামে অনেক সময়Noneফেরত দেওয়া বা চতুর্বিংশ অধ্যায়েরraiseব্যবহার করাই সৎ। এখানে0.0রাখা হয়েছে সরলতার জন্য — কিন্তু সিদ্ধান্তটি যে একটি সিদ্ধান্ত, সেটা জেনে রাখুন।
ডকস্ট্রিং
ফাংশনের প্রথম লাইনে একটি লেখা রাখলে সেটি হয়ে যায় তার নথি:
def average(values):
"""Return the mean of values, or 0.0 when there are none."""
if not values:
return 0.0
return round(sum(values) / len(values), 2)
print(average([1, 2, 3]))
print(average.__doc__)2.0
Return the mean of values, or 0.0 when there are none.কমেন্টের থেকে এর পার্থক্য হলো এটি প্রোগ্রামের ভেতরেই থেকে যায় — এডিটর এটি দেখায়, help(average) এটি ছাপে।
ভালো ডকস্ট্রিং বলে কী ফেরত আসে আর প্রান্তে কী হয়, কোডটা কীভাবে কাজ করে তা নয়। কোডটা তো নিচেই আছে।
একটা সম্পূর্ণ উদাহরণ
report.py:
# Three small functions, each doing one thing
def average(values):
"""Return the mean of values, or 0.0 when there are none."""
if not values:
return 0.0
return round(sum(values) / len(values), 2)
def grade(mark):
"""Turn a mark into a letter."""
if mark >= 80:
return "A"
if mark >= 70:
return "B"
if mark >= 40:
return "C"
return "F"
def summarise(name, marks):
"""Build one report line for a person."""
mean = average(marks)
return f"{name:<8} {len(marks):>2} papers avg {mean:>6} grade {grade(mean)}"
people = {
"rafi": [72, 88, 61],
"ahmed": [45, 38],
"dia": [],
}
for name, marks in people.items():
print(summarise(name, marks))rafi 3 papers avg 73.67 grade B
ahmed 2 papers avg 41.5 grade C
dia 0 papers avg 0.0 grade Fচারটি জিনিস লক্ষ করার মতো।
প্রতিটি ফাংশন একটি কাজ করে। average গড় বের করে, grade অক্ষর দেয়, summarise একটি লাইন গড়ে। কোনোটিই ছাপে না — ছাপার কাজটা একেবারে নিচের লুপে, একটিমাত্র জায়গায়। তাই এই রিপোর্টটি ফাইলে লিখতে হলে কেবল ওই এক লাইন বদলাতে হবে।
ফাংশন ফাংশনকে ডাকছে। summarise ডাকছে average আর grade। এটিই ফাংশনের আসল লাভ: ছোট ছোট নির্ভরযোগ্য টুকরো জোড়া দিয়ে বড় কাজ।
grade-এ কোনো else নেই। প্রতিটি return নিজেই থামিয়ে দেয়, তাই শর্তগুলো সমতল থাকে। নবম অধ্যায়ের নিয়মটি এখানেও খাটে: সবচেয়ে কঠিন শর্ত আগে — 80 আগে না লিখে 40 আগে লিখলে সবাই C পেত।
dia-র খালি লিস্টটি প্রোগ্রাম ভাঙেনি। গার্ডটি 0.0 দিয়েছে, grade সেটিকে F বানিয়েছে, আর রিপোর্টের সারিটি স্বাভাবিকভাবে ছাপা হয়েছে। প্রান্তিক অবস্থা একবার সামলানো হয়েছে, একটি জায়গায়।
কিছু ভাঙা অবস্থা ও তার সমাধান
NameError: name 'greet' is not defined — অথচ ফাংশনটি লেখা আছে ফাংশনটি ডাকা হয়েছে তার def লাইনটি চলার আগে। পাইথন ফাইলটি উপর থেকে নিচে পড়ে, আর def চলার আগে নামটি তৈরি হয় না। সব def উপরে রাখুন, আর ডাকার কোডটা নিচে।
TypeError: average() missing 1 required positional argument: 'values' কল করার সময় আর্গুমেন্ট দেওয়া হয়নি — average() লেখা হয়েছে, average(marks) নয়। বার্তাটি কোন প্যারামিটারটি বাদ পড়েছে তার নামও বলে দেয়।
ফাংশনটি None ফেরত দিচ্ছে return লেখা হয়নি, অথবা return লেখা আছে কিন্তু ভুল ইন্ডেন্টে — যেমন একটি if-এর ভেতরে, যেখানে সেই শর্তটি মেলে না। আরও একটি সাধারণ কারণ: print লেখা হয়েছে যেখানে return দরকার ছিল।
ফাংশনের ভেতরের ভেরিয়েবল বাইরে পাওয়া যাচ্ছে না সেটাই স্বাভাবিক — কেন, তা একবিংশ অধ্যায়ের বিষয়। আপাতত: যা বাইরে দরকার তা return করুন।
SyntaxError — def লাইনের শেষে কোলন নেই if আর for-এর মতোই, def লাইনটিও কোলনে শেষ হয়।
IndentationError: expected an indented block after function definition def লাইনের পর অন্তত একটি ইন্ডেন্ট করা লাইন থাকতে হবে।
ধাপ ৪ / ৬ — অনুমান
যাচাই করুন
ফাংশনটি print করে, return করে না। দুটি লাইন কী ছাপবে?
def double(x):
print(x * 2)
result = double(5)
print(result)- A10 None
- B10 10
- CNone 10
- D10
else ছাড়াই দুটি return। কী ছাপা হবে?
def check(mark):
if mark >= 40:
return "pass"
return "fail"
print(check(72))- Apass
- Bfail
- Cpass fail
- DNone
ফাংশনটি ফাইলেই আছে, তবু কী হবে?
print(greet("rafi"))
def greet(name):
return "hello " + name- A`NameError` — `def` লাইনটি চলার আগেই ফাংশনটি ডাকা হয়েছে
- Bhello rafi
- C`TypeError`
- D`SyntaxError`
উত্তর দিতে অ্যাকাউন্ট লাগবে
উত্তর মিলিয়ে দেখতে সাইন ইন করুন
প্রশ্নগুলো উপরে আছে, আর মাথায় মাথায় উত্তর ভেবে নেওয়াই আসল কাজ। সঠিক উত্তর, ব্যাখ্যা আর তিন ধাপের ইঙ্গিত দেখতে সাইন ইন করুন।
নিজে করুন
text_tools.py নামে একটি ফাইল লিখুন, যেখানে চারটি ফাংশন থাকবে — প্রতিটিতে একটি ডকস্ট্রিং, আর কোনোটিই print করবে না:
clean(text)— স্পেস ছাঁটে আর ছোট হাতের করেinitials(full_name)—"Rafi Ahmed"থেকে"RA"বানায়word_count(text)— শব্দ গোনে, আর খালি লেখায়0দেয়summarise(text)— উপরের তিনটিকে ডেকে একটি পড়ার মতো লাইন বানিয়ে ফেরত দেয়
তারপর ফাইলের নিচে কয়েকটি লেখা নিয়ে summarise ডেকে ফলগুলো ছাপান — ছাপার একমাত্র জায়গা সেটিই।
শেষে তিনটি পরীক্ষা করুন:
word_count("")ডাকুন। গার্ড ছাড়া কী হতো?summariseথেকেreturnমুছে দিয়ে তার জায়গায়printবসান, তারপর ফলটি একটি ভেরিয়েবলে রেখে ছাপান। কী দেখছেন, আর কেন?cleanফাংশনটির ডাক তারdef-এর উপরে সরিয়ে দিন, আর ত্রুটির বার্তাটি পড়ুন।
দ্বিতীয়টি এই অধ্যায়ের সবচেয়ে দামি তিন মিনিট। print আর return-এর পার্থক্য একবার নিজের চোখে দেখলে সেটা আর গুলিয়ে যায় না।
ধাপ ৬ / ৬
কঠিন করা — অধ্যায়ের কুইজ
সহজ থেকে কঠিন — দশটি প্রশ্ন, শেষেরগুলো ইচ্ছে করেই কঠিন।
সাইন ইন করে কুইজ দিন