ক্লাস এবং অবজেক্ট

পাইথন হচ্ছে অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং ল্যাঙ্গুয়েজ। অবজেক্ট হছে ডেটা এবং মেথড এর সমষ্টি। মেথড হচ্ছে ফাংশন, যা ঐ ডেটার উপর কাজ করে।

ক্লাস হচ্ছে অবজেক্ট এর ব্লু প্রিন্ট। একটা বাড়ীর স্কেচ এর কথা চিন্তা করি। এটা হচ্ছে ক্লাস। যার মধ্যে বাড়িটি কেমন হবে, কয়েকটি রুম, ফ্লোর, দরজা, জানালা ইত্যাদি সব থাকে। আর বাড়িটি হচ্ছে অবজেক্ট। বাড়িটির স্কেচ বা ব্লু প্রিন্ট ব্যবহার করে আমরা যত ইচ্ছে ততগুলো বাড়ি তৈরি করতে পারি। আর ক্লাস থেকে অবজেক্ট তৈরিকে বলে ইন্সট্যান্স (instance) তৈরি। মানে এক একটা অবজেক্ট হচ্ছে ক্লাসের এক একটা ইন্সট্যান্স।

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

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

ক্লাস থেকে অবজেক্ট তৈরি করাকে বলা হয় ইন্সটিশিয়েশন (instantiation) বা ইনিস্ট্যান্স (instance) তৈরি।

ক্লাস তৈরি করা

ক্লাস তৈরি করতে class কিওয়ার্ড ব্যবহার করতে হয়। এরপর ক্লাসের নাম দিতে হয়। ক্লাসের কি কি থাকবে, এরপর সেগুলো লিখতে হয়। যেমনঃ

class Car:
    pass

এখানে আমরা Car নামে একটা ক্লাস লিখেছি। ক্লাস তৈরির পর তা খালি থাকতে পারে না, এরর দেখাবে। কোন ফাংশন বা ক্লাস লিখে আমরা pass স্টেটমেন্ট ব্যবহার করতে পারি। তাহলে আর এরর দেখাবে না।

এই ক্লাস থেকে আমরা যত ইচ্ছে তত গুলো অবজেক্ট তৈরি করে নিতে পারব। যেমনঃ

class Car:
    pass

car_1 = Car()
car_2 = Car()

উপরের প্রোগ্রাম রান করলে কিছু হবে না। কারণ আমরা কিছু করতে বলিনি। এর আগে কন্সট্রাকটর সম্পর্কে জানা যাক।

কনস্ট্রাকটর
একটা ক্লাস থেকে অবজেক্ট তৈরি করার পর ঐ অবজেক্টকে ব্যবহার করার জন্য প্রস্তুত করতে কনস্ট্রাকটর ব্যবহৃত হয়। সাধারণত অবজেক্টের ডেটা মেম্বারের প্রাথমিক ভ্যালু গুলো সেট করতে কনস্ট্রাকটর ব্যবহৃত হয়।
পাইথনে কনস্ট্রাকটর তৈরি করা হয় __init__ মেথড দিয়ে। দুইটা আন্ডারস্কোর init এবং দুইটা আন্ডারস্কোর দিয়ে। প্রতিটা ক্লাস তৈরির পর আমাদের __init__() মেথড লিখতে হয়। ক্লাস থেকে কোন অবজেক্ট তৈরি করলে এই __init__() মেথড কল হবে। __init__() মেথডে self নামে একটা প্যারামিটার পাস করতে হয়। এই self মানে হচ্ছে আমরা ক্লাস থেকে যে অবজেক্ট তৈরি করব, সে অবজেক্টটা।

class Car:

    def __init__(self):
        print("Init method called.”)


car_1 = Car()

যা আউটপুট দিবেঃ

Init method called.

উপরে আমরা Car ক্লাস থেকে একটা অবজেক্ট তৈরি করেছি car_1 নামে। যখনি অবজেক্ট তৈরি করেছি, তখনি init মেথডটা কল হয়েছে। এর কাজ হচ্ছে অবজেক্ট তৈরি করলে ঐ অবজেক্টের বিভিন্ন ভ্যালু গুলো এসাইন করা। এই __init__() মেথডে আমরা অন্যান্য প্যারামিটার পাস করতে পারি। যখন একটি অবজেক্ট তৈরি করা হয়, তখনই কনস্ট্রাকটর কল হয়। যত গুলো অবজেক্ট তৈরি করা হয়, তত বার কন্সট্রাকটর কল করা হয়ঃ

class Car:

    def __init__(self):
        print("Init method called.”)


car_1 = Car()
car_2 = Car()

যা আউটপুট দিবেঃ

Init method called.
Init method called.

গাড়ির একটা নাম থাকবে। কি রঙ এর, তা থাকবে। Car ক্লাসে __init__() মেথডের ভেতর self এর পাশা পাশী আরো দুইটা প্যারামিটার পাস করব। একটা হচ্ছে name, আরেকটা হচ্ছে color। তো যখনি এই Car ক্লাস থেকে কোন অবজেক্ট তৈরি করব, তখন সাথে সাথে __init__() মেথড কল হবে। এবং এই name এবং color এর ভ্যালু এসাইন হবে।

class Car:

    def __init__(self, name, color):
        self.name = name
        self.color = color


car_1 = Car('Toyota Prius', 'Black')

যেমন আমরা Car ক্লাস থেকে car_1 অবজেক্ট তৈরি করার সময় দুইটা ভ্যালু পাস করেছি। একটা হচ্ছে name, আরেকটা color। আর এই ভ্যালু দুইটা এসাইন হয়েছে init মেথডের ভেতর, self.name এবং self.color এর মাধ্যমে।

ভ্যালু দুইটা এখন আমরা চাইলে এক্সেস করতে পারিঃ

class Car:

    def __init__(self, name, color):
        self.name = name
        self.color = color


car_1 = Car('Toyota Prius', 'Black')

print(car_1.name)
print(car_1.color)

যা আউটপুট দিবেঃ

Toyota Prius
Black

এই Car ক্লাস থেকে আমরা যত ইচ্ছে তত গুলো অবজেক্ট তৈরি করে নিতে পারব। এখনো হয়তো মনে হচ্ছে এই কাজ গুলোর জন্য ক্লাসের কি দরকার। মনে হতে পারে সিম্পল এই কাজের জন্য তো আরো বেশি কোড লিখতে হচ্ছে। আসলে প্রথম প্রথম তাই মনে হবে। এখন যদি ক্লাসের মেথড সম্পর্কে জানি, তাহলে ভুল ভাঙ্গবে।

অবজেক্টের মেথড

যেমন ক্লাস তৈরির সময় আমরা বিভিন্ন মেথড লিখতে পারি। তখন ঐ ক্লাস থেকে যত গুলো অবজেক্ট তৈরি করব, সব গুলো অবজেক্টের ক্ষেত্রে এই মেথড গুলো ব্যবহার করতে পারব। একটা উদাহরণ দেখিঃ

class Car:

    def __init__(self):
        pass

    def start(self):
        print(‘Started the car')

car_1 = Car()
car_1.start()

ক্লাস তৈরির সময় start নামে একটা মেথড লিখেছি। ক্লাস থেকে অবজেক্ট তৈরি করার পর আমরা এই মেথডটি কল করলে Started the car প্রিন্ট করে দিচ্ছে।

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

class Car:

    def __init__(self, name, color):
        self.name = name
        self.color = color

    def info(self):
        print("This " + self.name + " is " + str(self.color))

    def start(self):
        print('Started the car')


car_1 = Car('Toyota GT86', 'Black')
car_1.info()
car_1.start()

car_2 = Car('Ferrari Roma', 'Red')
car_2.info()

যা আউটপুট দিবেঃ

This Toyota GT86 is Black
Started the car
This Ferrari Roma is Red

এখানে info নামে একটা মেথড লিখেছি। তো এই মেথডের কাজ হচ্ছে যখনই কল করবে, তখনি নির্দিষ্ট গাড়ির তথ্য গুলো প্রিন্ট করে দিবে।

ফাংশনে প্যারামিটার পাস করা

আমরা চাইলে ক্লাসের মেথডে যে কোন ভ্যালু প্যারামিটার হিসেবে পাস করতে পারি। অন্য সব সাধারণ ফাংশনের মত। নিচের প্রোগ্রামটি দেখিঃ

class Calculator:
    def __init__(self):
        pass

    def add(self, num_1, num_2):
        self.num_1 = num_1
        self.num_2 = num_2
        return num_1 + num_2

calculator_1 = Calculator()

print(calculator_1.add(9, 5))

এখানে আমরা Calculator নামে একটা ক্লাস তৈরি করেছি যার মধ্যে একটা মাত্র মেথড রয়েছে add নামে। তো যখন এই মেথডটি কল করেছি, তখন দুইটা ভ্যালু পাস করেছি। মেথডের ভেতর ঐ ভ্যালু দুইটা নিয়ে যোগ করে রিটার্ণ করেছি। যা আমাদের সংখ্যা দুইটার যোগফল প্রিন্ট করে দিবে।

ইনহেরিটেন্স

একটা ক্লাস থেকে তার বিভিন্ন বৈশিষ্ট গুলো ব্যবহার করে নতুন ক্লাস তৈরি করা হচ্ছে ইনহেরিটেন্স। যেমন সকল মানুষ হচ্ছে Mammalia ক্লাসের। এখন মানুষের অনেক বৈশিষ্টই Mammalia এর সাথে মিলবে। তাই আমরা মানুষ নামের কোন ক্লাস তৈরি করলে আগে Mammalia নামক ক্লাসটি ইনহেরিট করব। এতে আমাদের অনেক গুলো কোড পূনরায় লিখতে হবে না। নতুন ক্লাস তৈরি করার সময় আগের কোন ক্লাস ইনহেরিট করতে চাইলে তা বলে দিতে হয়। যেমনঃ

class Mammalia:
	pass
class HomoSapiens(Mammalia):
	pass 

এখানে HomoSapiens নামে একটা ক্লাস তৈরি করেছি। যা Mammalia ক্লাস ইনহেরিট করেছে।

চাইলে একের অধিক ক্লাস ইনহেরিট করা যেতে পারে। তখন যে ক্লাস গুলো ইনহেরিট করব, সেগুলো কমা দিয়ে লিখতে হবে। যেমনঃ

class Animalia:
	pass 
class  Mammalia
	pass 
class HomoSapiens(Animalia, Mammalia):
	pass

আমরা একটি সাইন্টিফিক ক্যালকুলেটর (Scientific Calculator) তৈরি করতে চাই। সাইন্টিফিক ক্যালকুলেটরে যোগ বিয়োগ গুণ ভাগের পাশা পাশি আরো অনেক গুলো সুবিধে থাকে। যেমন একটা সংখ্যার সাইন মান বের করা। যেহেতু Calculator এ যোগ, বিয়োগ, গুণ ভাগ ইত্যাদি করা যায়। আমরা সাইন্টিফিক ক্যালকুলেটর তৈরির সময় আলাদা ভাবে ঐ Calculator ক্লাসের কোড গুলো না লিখে Calculator ক্লাসের সাথে আরো কিছু মেথড যুক্ত করে দিলেই আমাদের কাজ হয়ে যাবে। নিচের প্রোগ্রামটি দেখিঃ

import math

class Calculator:
    def __init__(self):
        pass

    def add(self, num_1, num_2):
        self.num_1 = num_1
        self.num_2 = num_2
        return num_1 + num_2

class ScientificCalculator(Calculator):
    def getSin(self, value):
        self.sin_value = value
        return math.sin(self.sin_value)
si_calc = ScientificCalculator()

print(si_calc.getSin(90))
print(si_calc.add(3, 8))

import math দিয়ে পাইথনের বিল্টইন ম্যাথ প্যাকেজ ইম্পোর্ট করেছি। যার মধ্যে ম্যাথ নিয়ে কাজ করার বিভিন্ন মেথড লেখা রয়েছে। প্যাকেজ সম্পর্কে আমরা পরের অধ্যায় জানতে পারব বিস্তারিত।
এখানে আমরা ScientificCalculator নামে একটা নতুন ক্লাস তৈরি করেছি। যার বলে দিয়েছি এটির কোন প্যারেন্ট ক্লাস আছে কিনা। আমাদের SiClac ক্লাসের প্যারেন্ট ক্লাস বা মূল ক্লাস হছে Calculator। এটাকে বলে ডিরাইভ করা। যখন আমরা বেজ ক্লাস বা মূলক্লাস থেকে ডিরাইভ করে নতুন ক্লাস তৈরি করব, তখন আমরা বেজ ক্লাসের সকল মেথড ব্যবহার করতে পারব।
আমাদের Scientific Calculator ক্লাসে একটা মেথড লিখছি, যা কোন সংখ্যা পাস করলে তার সাইন মান রিটার্ন করবে। আমরা চাইলে এখন আবার বেজ ক্লাস, Calculator এর মেথড ও ব্যবহার করতে পারি। যেমন si_calc.add() কল করলে দুইটা সংখ্যা পাস করলে আমাদের ঐ দুটা সংখ্যার যোগফল প্রিন্ট করে দিবে। প্যারেন্ট ক্লাস (এখানে Calculator) এর মেথড চাইল্ড ক্লাস (এখানে ScientificCalculator) এ ব্যবহার করতে পারা হচ্ছে ইনহেরিটেন্স (Inheritance)।

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

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

1 thought on “ক্লাস এবং অবজেক্ট”

Leave a Reply