আরও দুটো OOP building block এই অংশ সম্পূর্ণ করে: Python কীভাবে "এটা বাইরে থেকে ছোঁবেন না" সংকেত দেয়, আর Python-এর নিজস্ব বিল্ট-ইন ফাংশনের সাথে একটি অবজেক্টকে কীভাবে ভালোভাবে কাজ করাবেন।
কিছু ভাষায় আসল private/protected কীওয়ার্ড আছে যা ভাষা প্রয়োগ করে। Python-এ কোনো সত্যিকারের প্রাইভেট প্রপার্টি নেই — এর বদলে, একটি শুরুর আন্ডারস্কোর একটি প্রথা যা সংকেত দেয় "internal, এটা বাইরে থেকে ব্যবহার করবেন না", যা Python ব্লক করার বদলে আপনাকে সম্মান করতে বিশ্বাস করে:
class BankAccount:
def __init__(self):
self._balance = 0 # single underscore: "internal, please don't touch"
def deposit(self, amount):
self._balance += amount
def get_balance(self):
return self._balance
account = BankAccount()
account.deposit(500)
print(account.get_balance()) # 500
print(account._balance) # 500 — this works! Python doesn't block it, even though the underscore says not toএকক আন্ডারস্কোর স্বাভাবিক অভ্যাস
একটি দুটো আন্ডারস্কোর প্রিফিক্স (__balance) "name mangling" ট্রিগার করে, যা বাইরে থেকে দুর্ঘটনাক্রমে অ্যাক্সেসকে সত্যিকারভাবে বিশ্রী করে তোলে, যদিও তখনও অসম্ভব নয়। বাস্তবে, একটি একক আন্ডারস্কোর আর প্রথাকে বিশ্বাস করা বাস্তব Python কোডে একটি প্রপার্টিকে পুরোপুরি লক করার চেষ্টার চেয়ে অনেক বেশি প্রচলিত।
আপনি ইতিমধ্যে একটি দেখেছেন — __init__। Python-এ আরও অনেক বিশেষ মেথড আছে, সবগুলো __name__ প্যাটার্ন মেনে চলে, যা একটি অবজেক্টকে ভাষার নিজস্ব বিল্ট-ইন আচরণে যুক্ত হতে দেয়:
class Student:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Student: {self.name}"
s = Student("Priya")
print(s) # "Student: Priya" — print() calls __str__ automatically
print(str(s)) # same thing__str__ ছাড়া, print(s) <__main__.Student object at 0x...>-এর মতো অসহায়ক কিছু দেখাত। এটি সংজ্ঞায়িত করাই নিয়ন্ত্রণ করে এর বদলে কী দেখানো হবে।
| ডান্ডার মেথড | একটি অবজেক্টকে যার সাথে কাজ করতে দেয় |
|---|---|
| __init__ | Student(...) — একটি instance তৈরি করা |
| __str__ | print(obj), str(obj) |
| __len__ | len(obj) |
| __eq__ | obj1 == obj2 |
এই অংশে সেগুলো দেখানো হয়েছে যা আপনি ক্রমাগত ব্যবহার করবেন। আরও উন্নত যেকোনো কিছুর জন্য বিশেষ মেথডের সম্পূর্ণ তালিকা python.org-এ আছে।
@property একটি মেথডকে কোনো বন্ধনী ছাড়াই একটি সাধারণ attribute-এর মতো অ্যাক্সেস করতে দেয় — এভাবেই Python একটি getter তৈরি করে যা validation লজিকও চালাতে পারে, কলিং কোডকে না জানিয়েই যে এটা ভেতরে একটি মেথড:
class BankAccount:
def __init__(self):
self._balance = 0
@property
def balance(self):
return self._balance
@balance.setter
def balance(self, value):
if value < 0:
raise ValueError("Balance cannot be negative.")
self._balance = value
account = BankAccount()
account.balance = 500 # looks like a plain attribute, actually calls the setter
print(account.balance) # 500 — looks like a plain attribute, actually calls the getter
# account.balance = -10 # ValueError — the setter blocks thisএটি স্পষ্ট getter/setter মেথডের সুবিধা দেয় কোনো বয়লারপ্লেট ছাড়াই — কলিং কোড একটি সরাসরি attribute-এর মতোই সহজ থাকে, আর ক্লাসটি তখনও নিজের নিয়ম প্রয়োগ করতে পারে।