Skip to content

ফাংশন

ফাংশনের সঙ্গে পরিচয় আমাদের অনেক আগেই হয়ে গিয়েছে। প্রথমেই যখন Hello world প্রিন্ট করেছিলাম, তখনই আমরা print() ফাংশন ব্যবহার করেছি। এছাড়াও আরো অনেক ফাংশন ব্যবহার করেছি, যেমন input(), len(), type() ইত্যাদি। আবার আমরা turtle মডিউল যখন ব্যবহার করেছি, তখন টার্টলের অনেক ফাংশনও ব্যবহার করেছি, যেমন forward(), left(), right(), dot() ইত্যাদি। ফাংশনগুলো কী কাজ করে, এটি আমাদের জানতে হবে, কিন্তু কিভাবে কাজ করে, সেটি এখন আমাদের জানার প্রয়োজন নেই। এসব ফাংশন তৈরি করে দেওয়া না থাকলে আমাদেরকে অনেক বেশি কষ্ট করতে হতো। যেমন print() ফাংশনটি কিভাবে কাজ করবে, সেটি পাইথনের বিল্টইনস্ মডিউলে লেখা আছে (তবে এই মডিউলটি আমাদের ইমপোর্ট করতে হয় না)। তেমনি dot() কিভাবে কাজ করবে, সেটি লেখা আছে টার্টল মডিউলের ভেতরে। এই অধ্যায়ে আমরা দেখবো, কিভাবে ফাংশন তৈরি করতে হয়, কিভাবে মডিউল তৈরি করতে হয় এবং প্রয়োজনীয় কিছু ফাংশনের ব্যবহার।

আমরা কখন ফাংশন তৈরি করবো? যখন আমাদেরকে একটি নির্দিষ্ট কাজ করতে হবে এবং সেই কাজটি একাধিকবার করার প্রয়োজন হবে, তখন আমরা সেই কাজের জন্য একটি ফাংশন তৈরি করে ফেলবো। আবার কখনও কখনও একটি কাজ একবার করলেও আমরা সেটির জন্য আলাদা ফাংশন তৈরি করতে পারি, যেন কোড বুঝতে সহজ হয়। যেমন ধরা যাক, আমাকে কোনো প্রোগ্রামে অনেকবার দুটি সংখ্যা যোগ করতে হবে। তখন আমরা এই যোগ করার জন্য একটি ফাংশন তৈরি করে ফেলতে পারি এভাবে :

def add(n1, n2):
    return n1 + n2

আমরা দেখতে পাচ্ছি যে, ফাংশনের শুরুতে লিখতে হবে def, তাহলে পাইথন বুঝবে যে এখানে একটি ফাংশন তৈরি করা হচ্ছে (বা সংজ্ঞায়িত করা হচ্ছে, definition শব্দের প্রথম তিন অক্ষর def)। তারপর ফাংশনের নাম দিতে হবে। আমরা নাম দিয়েছি add। ফাংশনের নাম দেখে যেন বোঝা যায় যে, ফাংশনটি কী কাজ করবে। তারপরে প্রথম বন্ধনীর ভেতরে ফাংশনের প্যারামিটার লিখতে হবে। সব ফাংশনে প্যারামিটার থাকে না। প্যারামিটার থাকবে কী না এবং কয়টি, সেটি নির্ভর করে আমরা কী ফাংশন তৈরি করছি, তার ওপর। যেমন এখানে আমি তৈরি করছি দুটি সংখ্যার যোগফল বের করার ফাংশন। তাহলে তো আমাকে কোন দুটি সংখ্যা আমি যোগ করবো, সেগুলো জানতে হবে বা ইনপুট নিতে হবে। ফাংশনের ক্ষেত্রে প্যারামিটার হচ্ছে ইনপুট নেওয়ার পদ্ধতি। তারপরে একটি কোলন চিহ্ন দিতে হবে। পরের লাইন থেকে ফাংশনের ভেতরের কোড লিখতে হবে এবং সেগুলো ইনডেনটেশন করা থাকতে হবে, নইলে পাইথনের পক্ষে বোঝা সম্ভব হবে না যে কোন অংশ ফাংশনের ভেতরে আর কোন অংশ বাইরে। ফাংশন থেকে আবার এক বা একাধিক জিনিস ফেরত পাঠানো যায়, যাকে বলে রিটার্ন করা। আমাদের যেমন যোগফল ফেরত পাঠানো দরকার, তাই আমরা n1 + n2 এর মান রিটার্ন করছি। আমরা এখন ফাংশনটির ব্যবহার দেখবো। আমাদের কোনো নিয়মকানুন মুখস্থ করার প্রয়োজন নেই, চর্চা করে ও চিন্তা করে আমরা প্রোগ্রামিং শিখবো।

>>> def add(n1, n2):
...     return n1 + n2
... 
>>> n = 10
>>> m = 5
>>> result = add(n, m)
>>> print(result)
15
>>> 
>>> number1 = 10
>>> number2 = 10
>>> result = add(number1, number2)
>>> print(result)
20
>>> 
>>> n1 = 20
>>> n2 = 10
>>> print(add(n1, n2))
30
>>> print(add(2.5, 3.5))
6.0
>>>

আমরা ফাংশনটির বিভিন্ন রকম ব্যবহার দেখলাম। যেসব বিষয় খেয়াল করতে হবে, সেগুলো হচ্ছে –

  • যদিও ফাংশনের প্যারামিটার হিসেবে n1 ও n2 ব্যবহার করা হয়েছে, আমরা কিন্তু ফাংশন কল করার সময় যেকোনো নামের আর্গুমেন্ট ব্যবহার করতে পারি।
  • আমরা যখন ফাংশনটি সংজ্ঞায়িত বা ডিফাইন করছি বা সহজ বাংলায় ফাংশনটি তৈরি করছি, তখন যে n1, n2 লিখলাম, এগুলোকে বলে ফাংশনের প্যারামিটার (parameter)। আর আমরা যখন ফাংশনটি কল করছি, যেমন add(n, m) বা add(n1, n2) বা add(2, 3) এখানে n, m বা n1, n2 বা 2, 3 হচ্ছে আর্গুমেন্ট (argument)। নামগুলো মুখস্থ করতে হবে না, তবে জেনে রাখা ভালো। ভবিষ্যতে ইংরেজি বই পড়ার সময় কাজে লাগবে।
  • আর্গুমেন্ট হিসেবে ভ্যারিয়েবল ব্যবহার করা যায়, আবার সরাসরি বিভিন্ন সংখ্যাও ব্যবহার করা যায়।

ফাংশনের যে সবসময় প্যারামিটার থাকতেই হবে, সেরকম কোনো কথা নেই। আবার ফাংশন থেকে যে কোনো কিছু রিটার্ন করতে হবে, এমন কোনো কথা নেই। আমরা ফাংশন থেকে কোনো কিছু রিটার্ন না করলে পাইথন আপনাআপনি None রিটার্ন করে। এটি পরীক্ষা করে দেখা যেতে পারে। আবার অনেকসময় ফাংশন থেকে একাধিক জিনিসও রিটার্ন করতে হতে পারে। সেক্ষেত্রে যেসব জিনিস রিটার্ন করতে হবে, return স্টেটমেন্টের পর সেগুলো কমা দিয়ে পৃথক করে দিতে হবে। যেমন : return a, b, c।

আমরা টার্টল ব্যবহার করে বর্গক্ষেত্র আঁকার একটি প্রোগ্রাম তৈরি করেছিলাম। প্রোগ্রামটিতে আমরা বর্গক্ষেত্র আঁকার কাজটি একটি ফাংশন তৈরি করে করতে পারি।

def draw_square(side_length):
    for i in range(4):
        turtle.forward(side_length)
        turtle.left(90)

তাহলে একটি সম্পূর্ণ প্রোগ্রাম লিখে দেখি, সেই বৃত্ত তৈরির প্রোগ্রামটি। নিচের প্রোগ্রামটি সাদাকালো, তবে কেউ চাইলে বিভিন্ন রং ব্যবহার করতে পারে :

import turtle

def draw_square(side_length):
    for i in range(4):
        turtle.forward(side_length)
        turtle.left(90)

counter = 0
while counter < 90:
    draw_square(100)
    turtle.right(4)
    counter += 1

turtle.exitonclick()

অনুশীলনী: একটি ফাংশন তৈরি করতে হবে যা প্যারামিটার হিসেবে একটি বাহুর দৈর্ঘ্য নেবে এবং একটি সমবাহু ত্রিভূজ আঁকবে।

এখন আমরা কিছু উদাহরণের মাধ্যমে ফাংশন সম্পর্কে আরো জানবো।

def myfnc(x):
    print("inside myfnc", x)
    x = 10
    print("inside myfnc", x)

x = 20
myfnc(x)
print(x)

ওপরের প্রোগ্রামটি রান করলে আমরা আউটপুট পাবো এমন :

inside myfnc 20
inside myfnc 10
20

তাহলে আমরা দেখতে পেলাম, ভ্যারিয়েবলের নাম যদিও একই, কিন্তু myfnc-এর ভেতরে x-এর মান পরিবর্তন করে দিলেও ফাংশনের বাইরে x-এর মান পরিবর্তিত হয় নি। এর কারণ হচ্ছে myfnc যখন কল হয়, তখন সে আর্গুমেন্ট হিসেবে যেসব ভ্যারিয়েবল পায়, সেগুলোর একটা কপি তৈরি হয়। তাই myfnc-এর x আর তার বাইরের x আসলে দুটি আলাদা ভ্যারিয়েবল। একটি ফাংশনের ভেতরে যেসব ভ্যারিয়েবল তৈরি করা হয় সেগুলো হচ্ছে ওই ফাংশনের লোকাল (local) ভ্যারিয়েবল। ফাংশনের বাইরে তার অস্তিত্ব থাকে না।

ফাংশনের বাইরে যদি কোনো ভ্যারিয়েবল থাকে, তাহলে ফাংশনের ভেতর থেকে ওই ভ্যারিয়েবল পাওয়া যায়। একে বলে গ্লোবাল (global) ভ্যারিয়েবল। নিচের প্রোগ্রাম রান করলে সেটি আমরা দেখতে পাবো :

def myfnc(y):
    print("y =", y)
    print("x =", x)

x = 20
myfnc(x)

প্রোগ্রামের আউটপুট হবে এরকম :

y = 20
x = 20

এখন আমরা যদি myfnc এর বাইরে থেকে y-এর মান দেখতে চাই, সেটি কি সম্ভব? নিচের প্রোগ্রাম রান করলেই বুঝতে পারা যাবে।

def myfnc(y):
    print("y =", y)
    print("x =", x)

x = 20
myfnc(x)
print("y:", y)

আউটপুট হবে এরকম :

y = 20
x = 20
Traceback (most recent call last):
  File "fnc_test.py", line 7, in <module>
    print("y:", y)
NameError: name 'y' is not defined

অর্থাৎ y নামে কোনো কিছু পাওয়া যায় নি।

এখন আমরা দেখবো, ফাংশনের প্যারামিটারের ডিফল্ট (default) মান কিভাবে দেওয়া যায়।

def myfnc(y=10):
    print("y =", y)

x = 20
myfnc(x)
myfnc()

এই প্রোগ্রামে আমি দুইবার myfnc ফাংশন কল করলাম। প্রথমবার আর্গুমেন্ট হিসেবে x পাঠাচ্ছি। দ্বিতীয়বার কিছুই পাঠাচ্ছি না। কিন্তু ফাংশনের প্যারামিটারে আবার বলে দিয়েছি y=10। এর মানে হচ্ছে যদি কোনো আর্গুমেন্ট পাঠানো না হয়, তাহলে y-এর মান হবে 10, আর যদি কোনো আর্গুমেন্ট পাঠানো হয়, তাহলে আর্গুমেন্টে যেই ভ্যারিয়েবলটি পাঠানো হলো, সেই ভ্যারিয়েবলের মান y-তে কপি হবে।

এবারে আরেকটি প্রোগ্রাম লিখবো :

def myfnc(x, y=10, z):
    print("x =", x, "y =", y, "z =", z)

x = 5
y = 6
z = 7
myfnc(x, y, z)

ওপরের কোড যদি রান করি, তাহলে আউটপুট পাবো এরকম :

    def myfnc(x, y=10, z):
             ^
SyntaxError: non-default argument follows default argument

এই এররের অর্থ হচ্ছে আমরা যদি ডিফল্ট মান দেই, তাহলে তারপরে সবগুলো আর্গুমেন্টে ডিফল্ট মান থাকতে হবে। মানে আমরা যদি লিখতাম def myfnc(x, y=10, z=0) তাহলে এই এরর আর আসবে না। আমরা প্রোগ্রাম লিখে পরীক্ষা করে দেখি। নিচের প্রোগ্রামটি রান করে আউটপুট দেখে বুঝে নিতে হবে।

def myfnc(x, y=10, z=0):
    print("x =", x, "y =", y, "z =", z)

x = 5
y = 6
z = 7
myfnc(x, y, z)
myfnc(x, y)
myfnc(x)

আর আমরা যদি চাই যে, z-এর কোনো ডিফল্ট মান থাকবে না তাহলে এভাবে লিখতে হবে : myfnc(x, z, y = 10)। কিন্তু এভাবে লিখলে তো একটা সমস্যা আছে, দ্বিতীয় আর্গুমেন্ট যেটি পাঠাবো, সেটি তো z-এ আসবে, কারণ প্যারামিটারের নাম তো বিবেচনা করা হয় না, বরং প্রথমটি x-এ, দ্বিতীয়টি z-এ এবং তৃতীয়টি y-এ কপি হবে। কিন্তু পাইথনে একটি উপায় আছে যেখানে নির্দিষ্ট প্যারামিটারে নির্দিষ্ট মান পাঠানো যায়। নিচের উদাহরণে আমরা সেটি দেখবো।

def myfnc(x, z, y=10):
    print("x =", x, "y =", y, "z =", z)

myfnc(x = 1, y = 2, z = 5)
a = 5
b = 6
myfnc(x = a, z = b)
a = 1
b = 2
c = 3
myfnc(y = a, z = b, x = c)

প্রোগ্রামটি রান করলে নিচের মতো আউটপুট আসবে :

x = 1 y = 2 z = 5
x = 5 y = 10 z = 6
x = 3 y = 1 z = 2

পাইথনে সুযোগ-সুবিধা অনেক বেশি। তবে এখানে একটি কথা বলা প্রয়োজন। বইটি প্রথমবার পড়ার পরে বেশিরভাগ পাঠকেরই এত কিছু মনে থাকবে না এবং এটি খুবই স্বাভাবিক। এতে চিন্তিত হওয়ার কিছু নেই। বইটি দ্বিতীয় বা তৃতীয়বার পড়ার (এবং সেই সঙ্গে প্রতিবারই বইয়ের সব উদাহরণ ও অনুশীলনীগুলো করতে হবে) পর এগুলো মনে থাকবে।

আমরা চাইলে ফাংশনের ভেতরে লিস্টও পাঠাতে পারি। যেমন, এখন আমি একটি ফাংশন লিখবো, যেটিতে আর্গুমেন্ট হিসেবে একটি লিস্ট পাঠানো যাবে এবং আমরা সেই লিস্টের সংখ্যাগুলো যোগ করে যোগফল ফেরত পাঠাবো। যদিও লিস্টে আমরা যেকোনো কিছুই পাঠাতে পারি; কিন্তু যেহেতু যোগ করবো, তাই আমরা সংখ্যার লিস্ট পাঠাবো।

def add_numbers(numbers):
    result = 0
    for number in numbers:
        result += number
    return result

result = add_numbers([1, 2, 30, 4, 5, 9])
print(result)

এখন, ফাংশনের ভেতর ভ্যারিয়েবল পাঠানো আর লিস্ট পাঠানোর মধ্যে একটি পার্থক্য আছে। যে ফাংশনের ভেতরে লিস্ট পাঠানো হয়েছে, সেখানে যদি লিস্টটি পরিবর্তন করা হয়, তাহলে আসল লিস্টও পরিবর্তিত হয়ে যায়। এটিও আমরা একটি প্রোগ্রাম লিখে যাচাই করো নেবো। তবে তার আগে আমাদের আরো একটি জিনিস জেনে নিতে হবে। আমরা যদি লিস্টের কোনো নির্দিষ্ট উপাদান পেতে চাই, যেমন প্রথম, দ্বিতীয়, তৃতীয় ইত্যাদি, তাহলে আমরা তৃতীয় বন্ধনীর ভেতরে সেই সংখ্যাটি উল্লেখ করে দিতে পারি। একে বলা হয় ইনডেক্স। তবে পাইথনে লিস্টের ইনডেক্স কিন্তু 1 থেকে নয়, 0 থেকে শুরু হয়। অর্থাৎ, আমরা যদি লিস্টের প্রথম উপাদান একসেস করতে চাই, তাহলে আমরা লিস্টের নামের পর [0] লিখবো। country নামের একটি লিস্টে যদি পৃথিবীর সবগুলো দেশের নাম থাকে, আর সেই লিস্টের 50-তম দেশটি আমরা দেখতে চাই, তাহলে আমাদেরকে country[49] প্রিন্ট করতে হবে।

def test_fnc(li):
    li[0] = 10

my_list = [1, 2, 3, 4]
print("before function call", my_list)
test_fnc(my_list)
print("after function call", my_list)

প্রোগ্রামটি রান করলে আমরা আউটপুট পাবো এরকম :

before function call [1, 2, 3, 4]
after function call [10, 2, 3, 4]

এরকম হওয়ার কারণ কী? কারণ আমরা যখন একটি লিস্ট অন্য একটি ভ্যারিয়েবলে অ্যাসাইন করি, তাহলে নতুন কোনো লিস্ট তৈরি হয় না, বরং নতুন ভ্যারিয়েবল আর পুরনো ভ্যারিয়েবলে একই লিস্ট থাকে। সেটিও আমরা পরীক্ষা করে দেখবো পাইথন ইন্টারপ্রেটারে।

>>> list1 = [1, 2, 3, 4]
>>> list2 = list1
>>> print(list1)
[1, 2, 3, 4]
>>> print(list2)
[1, 2, 3, 4]
>>> list2[0] = 100
>>> print(list2)
[100, 2, 3, 4]
>>> print(list1)
[100, 2, 3, 4]

তাই ফাংশনের ভেতরে লিস্ট পাঠানোর সময় কিংবা আরেকটি ভ্যারিয়েবলে লিস্ট অ্যাসাইন করার সময় আমাদের সতর্ক হতে হবে। নইলে প্রোগ্রামে বাগ-এর সৃষ্টি হবে। কম্পিউটার প্রোগ্রামের ত্রুটিকে বলে বাগ (bug)।

আমরা যে একটু আগে লিস্টের উপাদানগুলো যোগ করার জন্য একটি ফাংশন লিখলাম, পাইথনে কিন্তু সেই কাজ করার জন্য একটি বিল্টইন ফাংশন আছে। আমাদের প্রয়োজন হলে আমরা সেই ফাংশন ব্যবহার করবো। তাহলে আমি উদাহরণের প্রোগ্রাম কেন লিখলাম? ফাংশনে কিভাবে লিস্ট পাঠাতে হয়, সেটি দেখানোর জন্য।

>>> li = [1, 2, 3]
>>> result = sum(li)
>>> print(result)
6

আমরা বইয়ের পরের অধ্যায়গুলোতে আরো বিভিন্ন বিল্টইন ফাংশন ব্যবহার করবো এবং নিজেরাও কিছু কিছু ফাংশন তৈরি করবো।

অনুশীলনী:

  • একটি ফাংশন তৈরি করতে হবে, যে প্যারামিটারে একটি লিস্ট নেবে এবং লিস্টের সংখ্যাগুলোর গড় নির্ণয় করে ফেরত পাঠাবে।
  • একটি নামতা প্রিন্ট করার ফাংশন তৈরি করতে হবে। ফাংশনে কোনো সংখ্যা পাঠালে সেই সংখ্যার নামতা প্রিন্ট করবে। আর কোনো কিছু না পাঠালে 1-এর নামতা প্রিন্ট করবে।

বিশেষ দ্রষ্টব্য – ফাংশন বিষয়ে বাংলা ভিডিও লেকচার দেখা যাবে এখানে – https://goo.gl/ozYWtv

উল্লেখ্য যে, ভিডিও লেকচারটি পাইথন ২ এর জন্য তৈরি করা হলেও, বেশিরভাগ প্রোগ্রামই পাইথন ৩-এও চলবে। আর, যেখানে print স্টেটম্যান্ট ব্যবহার করা হয়েছে, সেখানে print() ব্যবহার করতে হবে।

Published inUncategorized