ফাংশন (Function)

একটি ফাংশন হল কোডের একটি “খণ্ড” যা আপনি একাধিকবার লেখার পরিবর্তে বারবার ব্যবহার করতে পারেন। ফাংশন প্রোগ্রামারদের একটি সমস্যাকে ছোট ছোট খণ্ডে ভাঙতে সাহায্য করে, যার প্রত্যেকটি একটি নির্দিষ্ট কাজ সম্পাদন করে। একবার একজন প্রোগ্রামার একটি ফাংশন সংজ্ঞায়িত করলে, তারা যখনই প্রয়োজন তখনই এটিকে কল করতে পারে, কেবল তার নাম ব্যবহার করে। অতিরিক্তভাবে, কাজ করার জন্য, ফাংশনের জন্য সম্ভবত কিছু ইনপুট বা প্যারামিটারের প্রয়োজন হবে, যেগুলি প্রতিবার কল করার সময় ফাংশনে দেওয়া হয়। এতে করে হয় কি , একজন প্রোগ্রামার বারংবার একই লজিক / একই কোড লিখা থেকে মুক্তি পায়। আপনি প্রায় যখনই একটি প্রোগ্রাম লিখেছেন তখনই আপনি এই ধরনের ফাংশন ব্যবহার করেছেন ইতিমধ্যে।
 
যেমন , print() একটি ফাংশন যেটি পাইথন আমাদের জন্য বানিয়ে রেখেছে। এর কাজ কি ছিলো ? এর মধ্যে যাই লিখবো না কেন সেটি আমাদেরকে দেখানো হবে. কিন্তু কিভাবে দেখতে হবে, এসব নিয়ে কিন্তু আমরা মোটেই চিন্তা করি নি. আমরা শুধু কিছু ডাটা ওই print ফাংশন এর মধ্যে দিয়ে রেখেছি আর কাজ হয়ে গিয়েছে। কেননা , কিভাবে দেখতে হবে এই সমস্ত লজিকগুলো ফাংশনের ভিতরে লিখা আছে.
 

এরকম আরও অনেক ফাংশন পাইথন আমাদের জন্য বানিয়ে রেখেছে। যেগুলো দিয়ে আমরা অনেক কঠিন কঠিন কাজ সহজেই সমাধান করে ফেলতে পারি। এগুলোকে বলা হয় বিল্ট-ইন (built-in) ফাংশন। তবে , আমাদের নিজেদের সুবিধার জন্যই আমাদের নিজেদের লজিকগুলো একটি / একাধিক ফাংশন আকারে জমা রাখতে হয় , প্রায়ই। এই টাইপের ফাংশনকে আমরা বলি ইউজার-ডিফাইন (user-define) ফাংশন.

আমাদের স্টাডির মাথা ব্যাথা শুধু মাত্র কিভাবে আমরা ইউজার ডিফাইন ফাংশনগুলো লিখবো

এখন একটি ফাংশন লিখি আগে,

def func():
    print("Hello From Function")

আমরা এভাবে ফাংশনটি লিখবো , তার আগে সিনটেক্স এর সাথে একটু পরিচিত হই.

প্রথম লাইনটি হচ্ছে ফাংশনের শুরু। def কিওয়ার্ড দিয়ে যেকোনো ফাংশনের শুরু হয়। এরপর একটি স্পেস দিয়ে ফাংশনের নাম লিখবো। এই নামটি আপনাদের ইচ্ছা মতো যেকোনো নাম দিলেই হযে (তবে অর্থবোধক নাম হওয়া উচিত) . আমাদের এখানে func হচ্ছে ফাংশনের নাম। এরপর অবশ্যই প্রথম বন্ধনী [ () ] দিতে হবে , তারপর অবশ্যই কোলন [:] দিতে হবে

দ্বিতীয় লাইন থেকে শুরু হয় একটি ফাংশনের বডি (body) . তবে এখন থেকে ইন্ডেন্টেশন মেইনটেইন করে লিখতে হবে। এই লাইন থেকে যতক্ষণ পর্যন্ত ফাংশন শেষ না হয় ততক্ষন পর্যন্ত এই ইন্ডেন্টেশন মেইনটেইন করে লিখতে হবে।

ফাংশন কল করা

def func():
    print("Hello From Function")

func()

# output : Hello From Function

ফাংশনের বাইরে যেকোনো জায়গা থেকে ওই ফাংশন থেকে কল দেয়া যায়। তবে আমি যেখান থেকে কল দিবো এবং ফাংশনটি যদি একই পাইথন ফাইল-এ থাকে , তাহলে ফাংশনটি অবশ্যই কল দেয়ার উপরে লিখতে হবে.

যা হোক , ফাংশন কল দেয়ার সিনট্যাক্স হচ্ছে , আগে ফাংশনের নাম লিখবো পরে প্রথম বন্ধনী দিবো।
দেখা যাচ্ছে কল দেয়ার সাথে সাথে “Hello From Function” লিখা প্রিন্ট হয়েছে , কেননা আমরা ফাংশনের মধ্যে এই প্রিন্ট দিয়ে রেখেছিলাম।

নিচের উদাহরণটি লক্ষ্য করি

def func():
    print("Hello From Function")

func()
func()
func()

"""
Output

Hello From Function
Hello From Function
Hello From Function

"""

অর্থাৎ বুঝাই যাচ্ছে , আমরা চাইলে কিন্তু একটি ফাংশন যতবার খুশি ততবার লিখতে পারি। এবং একটি সেইম জিনিস করার জন্য আমাদেরকে সেইম কোড বার বার লিখা লাগছে না। শুধু মাত্র ফাংশন কল দিলেই হয়ে যাচ্ছে

আরেকটি উদাহরণ দেখি

def my_list_info():
    ls = [1,2,3]
    
    print(f"My list has {len(ls)} members . They are:")
    
    for each in ls:
        print(each)

my_list_info()


"""
Output
My list has 3 members . They are:
1
2
3
"""

এবারে এই ফাংশনটি নিজে নিজে বুঝার চেষ্টা করুন

আর্গুমেন্টস (Arguments)

ডেটা আর্গুমেন্ট হিসাবে ফাংশনের মধ্যে পাঠানো যায়। আর্গুমেন্টগুলি ফাংশনের নামের পরে, বন্ধনীর ভিতরে উল্লেখ করতে হয়। একাধিক আর্গুমেন্ট পাঠাতে চাইলে সেগুলো কমা দিয়ে আলাদা করুন।
 
নিচের উদাহরণে একটি আর্গুমেন্টসহ একটি ফাংশন রয়েছে। ফাংশনটি কল করলে, fname আর্গুমেন্টের মাধ্যমে first name পাঠানো হয়, যা ফাংশনের ভিতরে full name প্রিন্ট করতে ব্যবহৃত হয়:
 
def my_function(fname):
    print(fname + " Refsnes")


my_function("Emil")
my_function("Tobias")
my_function("Linus")
 
একটি ফাংশন এর দৃষ্টিকোণ থেকে:
* একটি প্যারামিটার হল ফাংশনের সংজ্ঞায় বন্ধনীর ভিতরে ভ্যারিয়েবল গুলো।
* একটি আর্গুমেন্ট হল সেই মান যা ফাংশনে পাঠানো হয় যখন এটি কল করা হয়।
 
নিচের ফাংশনটি দুটি আর্গুমেন্ট আশা করে এবং দুটি আর্গুমেন্ট পায়:
 
def my_function(fname, lname):
    print(fname + " " + lname)


my_function("Emil", "Refsnes")

আপনি একটি বা তিনটি আর্গুমেন্ট সহ ফাংশনটি কল করার চেষ্টা করলে, সেটি কাজ করবে না।

নিচের ফাংশনটি দুটি আর্গুমেন্ট আশা করে, কিন্তু মাত্র একটি পায়:

 

def my_function(fname, lname):     
    print(fname + " " + lname) 
my_function("Emil")
 
Arbitrary Arguments (*args)
ফাংশনে কতগুলি আর্গুমেন্ট পাস করা হবে সেটা অনির্দিষ্ট (arbitrary) হলে, ফাংশনের সংজ্ঞায় প্যারামিটার নামের আগে একটি * যোগ করুন। এইভাবে ফাংশনটি একাধিক আর্গুমেন্ট নিতে পারবে এবং সেই অনুযায়ী আইটেমগুলি অ্যাক্সেস করতে পারে:
 
def my_function(*kids):
    print("The youngest child is " + kids[2])
my_function("Emil", "Tobias", "Linus")

পাইথন ডকুমেন্টেশনে Arbitrary Arguments প্রায়ই *args দিয়ে উল্লেখ করা হয়।

return statement

কোন একটি ফাংশন থেকে যদি আমরা কিছু পাঠাতে চাই তাহলে ওই ডাটা টি রিটার্ন করবো। যেমন

def person():
    return "SHafiul TareQ"

person()

এখন এটিকে কল দেয়া হলেও কিন্তু এটি কিছুই দেখাবে না. আমরা চাইলে সরাসরি প্রিন্ট এর মধ্যে কল করতে পারি। (যেহেতু ডাটা রিটার্ন হচ্ছে)

def person():
    return "SHafiul TareQ"
    
print( person() )

"""
output
SHafiul TareQ
"""

অথবা চাইলে কোন ভ্যারিয়েবল এর মধ্যেও স্টোর করতে পারি এই রিটার্ন করা ভ্যালুটি

def person():
    return "SHafiul TareQ"
    
name = person() 
print(name)

# output: SHafiul TareQ

তবে একটি ফাংশন থেকে একবার রিটার্ন হয়ে গেলে সেটির নিচে এরই যাই লিখি না কেন , একটি কোড ও এক্সিকিউট হবে না। যেমন,

def factorial(number):
    print("Calculating ... ")
    
    sum = 1
    for i in range(1, number+1):
        sum = sum * i
        
    return sum
    
    print("Calculation done ")
    

fact = factorial(5)
print(fact)

"""
Calculating ... 
120
"""

দেখা যাচ্ছে যে , রিটার্ন করার পরে “Calculation done ” এই লিখাটি প্রিন্ট হয় নি

Keyword Arguments

Arbitrary Arguments এ চাইলে key = value সিনট্যাক্স ব্যবহার করে আর্গুমেন্ট পাঠাতে পারেন। এগুলোকে কীওয়ার্ড আর্গুমেন্ট বলা হয়। এখানে আর্গুমেন্টের ক্রম কোন ব্যাপার না।

def my_function(child3, child2, child1):     
    print("The youngest child is " + child3) 
my_function(child1 = "Emil", child2 = "Tobias", child3 = "Linus")

 

Arbitrary Keyword Arguments (**kwargs)

ফাংশনে কতগুলি কীওয়ার্ড আর্গুমেন্ট পাঠানো হবে তা অনির্দিষ্ট হলে, ফাংশনের সংজ্ঞায় প্যারামিটার নামের আগে দুটি তারকাচিহ্ন (star) যুক্ত করুন: ** । এইভাবে ফাংশন আর্গুমেন্টের একটি Dictionary পাবে, এবং সেই অনুযায়ী আইটেমগুলি অ্যাক্সেস করতে পারবে:
 
def my_function(**kid):     
    print("His last name is " + kid["lname"]) 
my_function(fname = "Tobias", lname = "Refsnes")

কিওয়ার্ড আর্গুমেন্ট প্রায়ই পাইথন ডকুমেন্টেশনে **kwargs হিসাবে ব্যবহার করা হয়।

Default Parameter Value

নিচের উদাহরনে দেখানো হয়েছে, কিভাবে একটি প্যারামিটারের জন্য ডিফল্ট ভ্যালু ব্যবহার করা যায়। যদি আর্গুমেন্ট ছাড়াই ফাংশনকে কল করি, সেটি ডিফল্ট মান ব্যবহার করে:
 
def my_function(country = "Norway"):
    print("I am from " + country)

my_function("Sweden")
my_function("India")
my_function()
my_function("Brazil")
 
আর্গুমেন্টে লিস্ট পাঠানো (Passing a List as an Argument)
 
একটি ফাংশনে স্ট্রিং, ইন্টিজার, লিস্ট, ডিকশনারি এরকম যেকোনো ডেটা টাইপের আর্গুমেন্ট পাঠানো যাবে এবং ফাংশনের ভিতরে প্যারামিটারটাও সেই ডেটা টাইপের হিসাবে বিবেচিত হবে।
নিচে আর্গুমেন্ট হিসাবে একটি লিস্ট পাঠানো হয়েছে, এটি ফাংশনে পৌঁছে লিস্ট হিসাবেই থাকছে।
 
def my_function(food):
    for x in food:
        print(x)


fruits = ["apple", "banana", "cherry"]

my_function(fruits)
 
পাস (pass) স্টেটমেন্ট
 
ফাংশন ডেফিনেশন খালি হতে পারে না, তবে যদি কোনো কারণে কোনো বিষয়বস্তু ছাড়া ফাংশনের ডিফাইন করতে হয়, তাহলে error এড়াতে পাস(pass) স্টেটমেন্ট রাখুন।
 
def myfunction():
    pass
 
রিকারশন (Recursion)

পাইথন ফাংশন রিকারশনও সাপোর্ট করে, যার মানে হচ্ছে একটি ডিফাইন্ড ফাংশন নিজেকে নিজেই কল করতে পারে।

 
রিকারশন একটি সাধারণ গাণিতিক এবং প্রোগ্রামিং ধারণা। এর মানে হল যে একটি ফাংশন নিজেকে নিজেই কল করে। এটির সুবিধা রয়েছে যে আপনি ফলাফলে পৌঁছানোর জন্য ডেটা লুপ করতে পারেন।
ডেভেলপারদের রিকারশন ব্যবহারে একটু সতর্ক থাকা উচিত। কারণ ঠিকমত লেখা না হলে, ফাংশনটির এক্সিকিউশন কখনই শেষ হবে না এবং এটি অতিরিক্ত পরিমাণে মেমরি বা প্রসেসর ব্যবহার করবে। যাইহোক, যখন সঠিকভাবে লেখা হয়, তখন রিকারশন প্রোগ্রামিং এর জন্য খুবই চমৎকার পদ্ধতি হতে পারে।
নিচের উদাহরণে, tri_recursion() ফাংশনে আমরা k ভেরিয়েবলটি প্রতিবার পুনরাবৃত্তি করার সময় এক এক করে কমে এবং ফাংশনটি থেকে নিজেকে কল দেয়। পুনরাবৃত্তি শেষ হয় যখন k এর মান শুন্যতে নেমে আসে।
এটি ঠিক কীভাবে কাজ করে তা প্রথম প্রথম বুঝতে কিছুটা সময় লাগতে পারে, তাই ডিবাগ করে ভ্যারিয়েবলের মানগুলো কিভাবে পরিবর্তন হয় তা দেখা বোঝার চেষ্টা করা যেতে পারে।
 
def tri_recursion(k):
   if k > 0:
      result = k + tri_recursion(k - 1)
      print(result)
   else:
      result = 0
   return result

print("\n\nRecursion Example Results")
tri_recursion(6)

Output:

Recursion Example Results
1
3
6
10
15
21

 

 
উদাহরন

উদাহরন ১

# make a function that check even or odd
def check_number(number):
    if number % 2 == 0:
        return True
    return False

inp = int(input("Enter a number : "))
if check_number(inp):
    print("Number is even")
else:
    print("Number is odd")

উদাহরন ২

# check a string palindrom or none

def reverse(str):
    return str[::-1]

def check_palindrome(str):
    if str == reverse(str):
        return True
    return False

inp = input("Enter a string : ")
if check_palindrome(inp):
    print(f"{inp} is a palindrome")
else:
    print(f"Not a palindrome")

উদাহরণ ৩

# Python program to check if year is a leap year or not

def check_leap_year(year:int):

    if (year % 400 == 0) and (year % 100 == 0):
        print("{0} is a leap year".format(year))
    
    elif (year % 4 ==0) and (year % 100 != 0):
        print("{0} is a leap year".format(year))
    
    else:
        print("{0} is not a leap year".format(year))

year = input()
check_leap_year(int(year))

উদাহরণ ৪

def recur_factorial(n):  
   if n == 1:  
       return n  
   else:  
       return n*recur_factorial(n-1)  
# take input from the user  
num = int(input("Enter a number: "))  
# check is the number is negative  
if num < 0:  
   print("Sorry, factorial does not exist for negative numbers")  
elif num == 0:  
   print("The factorial of 0 is 1")  
else:  
   print("The factorial of",num,"is",recur_factorial(num))

উদাহরণ ৫

def star_piramid(num):
    for i in range(num):
        total = "*"*i 
        print(total) 
        star_piramid(10)
এসো নিজে করি
* একটি ফাংশন লিখুন যেটি প্যারামিটার হিসেবে তিনটি ইন্টেজার ভ্যারিয়েবল নিবে,
   এবং সবচেয়ে বড় সংখ্যা বের করে আউটপুট দিবে।
* একটি ফাংশন লিখুন যেটি First Name, Last Name নিবে এবং Full Name রিটার্ন করবে।
* একটি ক্যালকুলেটর বানান, যেখানে প্রতিটি গাণিতিক অপারেশন (যোগ, বিয়োগ, গুন, ভাগ)
   এর জন্য আলাদা আলাদা ফাংশন থাকবে।
*  ১০০ এর মধ্যকার সকল ফিবোনাচ্চি নম্বর প্রিন্ট করার একটি ফাংশন লিখুন।
   ফিবোনাচ্চি এর প্রথম দুটি নম্বর প্যারামিটার হিসাবে পাস করুন।
* ১০০ এর মধ্যকার সকল ফিবোনাচি নম্বর প্রিন্ট করুন রিকার্সিভ ফাংশন ব্যবহার করে।
 
ইন্টারভিউ প্রশ্নোত্তর
# গুরুত্বপূর্ন প্রশ্নসমুহ
* Function Declaration এবং Function Definition এর মধ্যে পার্থক্য কি ?
* Function এর রিটার্ন বলতে কি বুঝায় ?
* Empty Function কিভাবে ডিক্লেয়ার করা যায় ?
* *args এবং **kwargs এর মধ্যে পার্থক্য কি ব্যাখ্যা করুন।
* পাইথনে উদাহরণ সহ রিকার্রসিভি ফাংশন ব্যাখ্যা করুন