அடிப்படை

Python-இல் வகுப்புகளும் OOP-உம்: __init__, self, முறைகள், மரபுரிமை மற்றும் dataclass

புதுப்பிக்கப்பட்டது: · Skillaria.Top

Python OOP வகுப்புகளை அடிப்படையாகக் கொண்டது: வகுப்பு புலங்களையும் முறைகளையும் விவரிக்கிறது, பொருள்கள் (நிகழ்வுகள்) வகுப்பை அழைப்பதன் மூலம் உருவாகின்றன; __init__ புலங்களை நிரப்புகிறது, self தற்போதைய பொருளைச் சுட்டுகிறது. மரபுரிமை பெற்றோரின் நடத்தையை எடுத்து சில முறைகளை மாற்ற அனுமதிக்கிறது; @dataclass தரவைச் சேமிக்கும் வகுப்புகளுக்கு __init__, __repr__ மற்றும் __eq__ ஐத் தானாக உருவாக்குகிறது.

Python-இல் வகுப்பு ஒரு வரைவுத் திட்டம் (blueprint): அது பொருள் எந்தத் தரவைச் சேமிக்கும், அதனுடன் என்ன செய்ய முடியும் என்று விவரிக்கிறது. பொருள் (நிகழ்வு) அந்தத் திட்டத்தின்படி செய்யப்பட்ட குறிப்பிட்ட பொருள். Python OOP மூன்று விஷயங்களின் மேல் நிற்கிறது: முறைகளுடன் கூடிய வகுப்புகள், மரபுரிமை, மற்றும் __init__, __repr__ போன்ற சிறப்பு முறைகள். ஒரே எடுத்துக்காட்டில் — செலவுக் கணக்கு — எல்லாவற்றையும் வரிசையாகப் பார்ப்போம்.

அகராதிகள் இருக்கும்போது வகுப்புகள் எதற்கு

தரவை அகராதியில் சேமிக்கலாம்: {"title": "காபி", "amount": 250}. பிரச்சனை என்னவென்றால், அகராதிக்கு எந்த விசைகள் சரி என்று தெரியாது. expense.get("amout", 0) என்ற எழுத்துப்பிழை பிழை தராது — பூஜ்ஜியம் திரும்பும், அறிக்கை அமைதியாகப் பொய் சொல்லத் தொடங்கும்.

வகுப்புப் பொருளின் புலங்கள் முன்கூட்டியே அறிவிக்கப்பட்டவை. இல்லாத பண்புக்கூறை அணுகினால் உடனே AttributeError வரும்; நவீன Python சரியான பெயரையும் பரிந்துரைக்கும். மேலும் வகுப்பு தரவையும் அதன் மீதான செயல்களையும் ஒரே இடத்தில் வைத்திருக்கிறது: செலவு தானே வரியுடன் தொகையைக் கணக்கிடும், அறிக்கை தானே மொத்தத்தைக் கணக்கிடும்.

Python-இல் வகுப்பை உருவாக்குவது

வகுப்பு class சொல்லால் அறிவிக்கப்படுகிறது; பெயர் PEP 8 மரபின்படி CamelCase-இல். எளிய வகுப்பு எடுத்துக்காட்டு:

class Expense:
    def __init__(self, title, amount):
        self.title = title
        self.amount = amount

coffee = Expense("காபி", 250)
taxi = Expense("டாக்ஸி", 300)
print(coffee.title, coffee.amount)   # காபி 250

Expense("காபி", 250) அழைப்பு ஒரு புதிய நிகழ்வை உருவாக்குகிறது. coffee மற்றும் taxi ஒரே வகையின் இரண்டு வெவ்வேறு பொருள்கள், ஒவ்வொன்றுக்கும் தனித்தனி புல மதிப்புகள். பொருள் இந்த வகுப்பைச் சேர்ந்ததா என்று isinstance(coffee, Expense) சரிபார்க்கலாம் — True தரும்.

__init__ தொடக்க முறை

__init__-ஐ பெரும்பாலும் வகுப்பின் கன்ஸ்ட்ரக்டர் என்று அழைக்கிறோம், ஆனால் துல்லியமாகச் சொன்னால் அது துவக்கி (initializer). பொருளை உருவாக்குவது __new__ முறை; __init__ அதன் பின்னர் உடனே அழைக்கப்பட்டு, கொடுக்கப்பட்ட வாதங்களை புலங்களில் வைக்கிறது. அதிலிருந்து எதையும் திருப்ப வேண்டியதில்லை (துல்லியமாகச் சொன்னால் அது None தர வேண்டும்).

__init__-இல் உள்ளீட்டுத் தரவைச் சரிபார்ப்பது வசதியானது; அப்போது நிரலில் தவறான பொருள்கள் உருவாகாது:

class Expense:
    def __init__(self, title, amount):
        if amount < 0:
            raise ValueError("தொகை எதிர்மறையாக இருக்க முடியாது")
        self.title = title
        self.amount = amount

Python-இல் self என்றால் என்ன

self என்பது முறை தற்போது வேலை செய்யும் அதே பொருளின் குறிப்பு. coffee.with_tax() என்று எழுதும்போது Python உண்மையில் Expense.with_tax(coffee) என்று அழைத்து பொருளை முதல் வாதமாக அனுப்புகிறது. அதனால் முறையின் அறிவிப்பில் self முதலில் வரும்; அழைக்கும்போது அது எழுதப்படுவதில்லை.

self ஒரு சிறப்புச் சொல் அல்ல, ஒரு மரபு: தொழில்நுட்ப ரீதியாக அளவுருவை எந்தப் பெயரிலும் வைக்கலாம், ஆனால் யாரும் அப்படிச் செய்வதில்லை. தொடக்கநிலையாளரின் பொதுவான தவறு — முறையின் அறிவிப்பில் self-ஐ மறப்பது. அப்போது அழைப்பு TypeError: Expense.with_tax() takes 0 positional arguments but 1 was given உடன் விழும்.

முறைகளும் சிறப்பு முறைகளும்

முறை என்பது வகுப்புக்குள் அறிவிக்கப்பட்ட செயல்பாடு. அது self மூலம் பொருளின் புலங்களைப் பார்க்கும்:

class Expense:
    def __init__(self, title, amount):
        self.title = title
        self.amount = amount

    def with_tax(self, rate=0.2):
        return self.amount * (1 + rate)

    def __repr__(self):
        return f"Expense({self.title!r}, {self.amount})"

coffee = Expense("காபி", 250)
print(coffee.with_tax())   # 300.0
print(coffee)              # Expense('காபி', 250)

__repr__ இல்லையென்றால் வெளியீடு <__main__.Expense object at 0x7f...> போல இருக்கும் — பிழைதிருத்தத்துக்கு பயனற்றது. இருபுறமும் இரட்டை அடிக்கோடுகள் உள்ள முறைகளை சிறப்பு (dunder) முறைகள் என்கிறோம்: அவற்றை Python தானே அழைக்கும். __str__ பயனருக்கான அழகான வெளியீட்டைக் கவனிக்கும், __eq__ == ஒப்பீட்டை, __len__ len(obj)-ஐ.

@classmethod மற்றும் @staticmethod

சாதாரண முறை பொருளுடன் வேலை செய்கிறது. @classmethod அலங்கரிக்கப்பட்ட முறை முதல் வாதமாக வகுப்பையே (cls) பெறுகிறது — அதை மாற்றுக் கன்ஸ்ட்ரக்டராகப் பயன்படுத்துவது வழக்கம். @staticmethod எந்தப் பொருளையும் வகுப்பையும் பெறுவதில்லை: அது வகுப்புடன் தர்க்கரீதியாகத் தொடர்புடைய சாதாரண செயல்பாடு.

class Expense:
    def __init__(self, title, amount):
        self.title = title
        self.amount = amount

    @classmethod
    def from_csv(cls, line):
        title, amount = line.split(";")
        return cls(title, float(amount))

    @staticmethod
    def is_valid_amount(value):
        return value >= 0

e = Expense.from_csv("மதிய உணவு;520")
print(e.amount)                    # 520.0
print(Expense.is_valid_amount(-1)) # False

வகுப்பின் அழிப்பான்: __del__

Python-இல் __del__ முறை உண்டு; குப்பை சேகரிப்பான் பொருளை அழிப்பதற்கு முன் அது அழைக்கப்படுகிறது. வளங்களை விடுவிக்க அதை நம்ப வேண்டாம்: அழைக்கப்படும் நேரம் உத்தரவாதமற்றது. கோப்புகளுக்கும் இணைப்புகளுக்கும் with சூழல் மேலாளரையோ வெளிப்படையான close() முறையையோ பயன்படுத்துங்கள்.

வகுப்பின் பண்புக்கூறுகளும் பொருளின் பண்புக்கூறுகளும்

self.name = ... மூலம் அமைக்கப்படும் புலங்கள் குறிப்பிட்ட பொருளுக்குச் சொந்தமானவை. வகுப்பின் உடலில் நேரடியாக அறிவிக்கப்பட்ட மாறிகள் வகுப்பின் பண்புக்கூறுகள்: அவை எல்லா நிகழ்வுகளுக்கும் பொதுவானவை. வகுப்பின் மாறிலிகளை இப்படித்தான் வைப்பார்கள்.

class Expense:
    CURRENCY = "INR"          # வகுப்பு பண்புக்கூறு, மாறிலி

    def __init__(self, title, amount):
        self.title = title    # பொருளின் பண்புக்கூறுகள்
        self.amount = amount

a = Expense("காபி", 250)
b = Expense("தேநீர்", 150)
print(a.CURRENCY, Expense.CURRENCY)   # INR INR

ஆபத்தான பொறி — மாற்றக்கூடிய வகுப்புப் பண்புக்கூறு. வகுப்பின் உடலில் rows = [] என்று அறிவித்து self.rows.append(...) மூலம் சேர்த்தால், அந்தப் பட்டியல் எல்லாப் பொருள்களுக்கும் பொதுவாகிவிடும். மாற்றக்கூடிய புலங்களை எப்போதும் __init__-இல் உருவாக்குங்கள்.

பொருளின் புலங்களை vars(obj) அல்லது obj.__dict__ மூலம் பார்க்கலாம்; சரத்திலிருந்து பெயரால் பண்புக்கூறைப் படிக்க — getattr(obj, "amount").

வகுப்பின் பண்புகள்: @property

பண்பு (property) என்பது வெளியிலிருந்து அடைப்புகள் இல்லாமல் சாதாரண புலம் போலப் படிக்கப்படும் முறை. கணக்கிடப்படும் மதிப்புகளுக்கு இது வசதியானது: அறிக்கையின் மொத்தத்தைத் தனியாகச் சேமிக்கத் தேவையில்லை, அதைப் புதுப்பிக்க மறக்கவும் மாட்டீர்கள்.

class Report:
    def __init__(self):
        self.rows = []

    def add(self, expense):
        self.rows.append(expense)

    @property
    def total(self):
        return sum(e.amount for e in self.rows)

r = Report()
r.add(Expense("காபி", 250))
r.add(Expense("டாக்ஸி", 300))
print(r.total)   # 550

எழுதுவதைக் கட்டுப்படுத்த வேண்டுமென்றால் @total.setter மூலம் setter சேர்க்கலாம். Setter இல்லாமல் r.total = 0 என்று ஒதுக்கினால் AttributeError வரும்.

உட்பொதித்தல் (encapsulation) பற்றி: Python-இல் கண்டிப்பான அர்த்தத்தில் தனிப்பட்ட புலங்கள் இல்லை. ஒரு அடிக்கோடு (_cache) "வெளியிலிருந்து தொடாதீர்கள்" என்ற ஒப்பந்தம்; இரண்டு அடிக்கோடுகள் (__secret) பெயர் திரிபை (name mangling) இயக்குகின்றன — வாரிசு தற்செயலாக அந்தப் புலத்தை மேலெழுதாமல் இருக்க.

Python-இல் வகுப்பு மரபுரிமை

மரபுரிமை ஒரு பெற்றோர் வகுப்பின் அடிப்படையில் குழந்தை வகுப்பை உருவாக்க அனுமதிக்கிறது: வாரிசு எல்லா புலங்களையும் முறைகளையும் பெறும், தேவையானவற்றை மேலெழுதும். பெற்றோர் வகுப்பு அடைப்புக்குள் குறிக்கப்படும்.

class MonthlyReport(Report):
    def __init__(self, month):
        super().__init__()        # பெற்றோரின் __init__-ஐ அழை
        self.month = month

    def add(self, expense):       # முறையை மேலெழுதுதல்
        print(f"[{self.month}] + {expense}")
        super().add(expense)      # பெற்றோரின் நடத்தையைத் தக்கவை

m = MonthlyReport("அக்டோபர்")
m.add(Expense("காபி", 250))   # [அக்டோபர்] + Expense('காபி', 250)
print(m.total)                # 250 — பண்பு மரபுரிமையாகக் கிடைத்தது

super() பெற்றோரின் முறைகளை அழைப்பதற்கான இடைநிலைப் பொருளைத் தரும். குழந்தையின் __init__-இல் super().__init__()-ஐ மறப்பது உன்னதப் பிழை: rows புலம் உருவாகாது, முதல் add AttributeError-உடன் விழும்.

உறவைச் சரிபார்க்க issubclass(MonthlyReport, Report). Python 3-இல் எல்லா வகுப்புகளும் மறைமுகமாக object-இலிருந்து மரபுரிமை பெறுகின்றன — அதனால்தான் அடிப்படை __repr__, __eq__ போன்ற முறைகள் வருகின்றன. Python பல மரபுரிமையையும் (class C(A, B)) ஆதரிக்கிறது; முறைகள் தேடப்படும் வரிசையை C.__mro__ காட்டும்.

Python-இல் சுருக்க வகுப்பு (abstract class)

சுருக்க வகுப்பு ஒரு இடைமுகத்தை வரையறுக்கிறது: வாரிசுகள் எந்த முறைகளைச் செயல்படுத்த வேண்டும். அதன் பொருளை உருவாக்க முடியாது. இதற்கு abc தொகுதி:

from abc import ABC, abstractmethod

class Exporter(ABC):
    @abstractmethod
    def export(self, report): ...

class CsvExporter(Exporter):
    def export(self, report):
        return "\n".join(f"{e.title};{e.amount}" for e in report.rows)

Exporter()   # TypeError: Can't instantiate abstract class Exporter ...

எல்லா சுருக்க முறைகளையும் செயல்படுத்தாத வாரிசும் சுருக்கமாகவே இருக்கும்; அதன் பொருளை உருவாக்கினாலும் அதே பிழை வரும்.

ஆழமான படிநிலைகளுக்குப் பதிலாக கூட்டமைப்பு (composition)

மரபுரிமை பற்றி அறிந்ததும் படிநிலைகளைக் கட்ட ஆசை வரும்: அடிப்படைச் செலவு, பண-செலவு, ரூபாய்-செலவு — இப்படி ஐந்து நிலைகள் வரை. Python-இல் இது அரிதாகவே எழுதப்படுகிறது. மரபுரிமை "என்பது" உறவை விவரிக்கிறது; கூட்டமைப்பு "கொண்டுள்ளது" உறவை: அறிக்கை செலவுகளின் பட்டியல் அல்ல, அதை rows புலத்தில் கொண்டுள்ளது.

நடைமுறை விதி: வேறொரு பொருளின் திறனை மட்டும் பயன்படுத்த வேண்டுமென்றால் அதை ஒரு புலமாக வையுங்கள், மரபுரிமை பெறாதீர்கள். தரவுக்கு பெரும்பாலும் dataclass போதும்; தர்க்கத்தை சாதாரண செயல்பாடுகளில் வைக்கலாம்.

Python dataclass: திரும்பத் திரும்பக் குறியீடு இல்லாத வகுப்பு

முக்கியமாகத் தரவைச் சேமிக்கும் வகுப்புகளுக்கு __init__, __repr__ மற்றும் __eq__-ஐ கைமுறையாக எழுதுவது சோர்வூட்டும். dataclasses தொகுதியின் @dataclass அலங்காரி அவற்றை புலங்களின் குறிப்புகளிலிருந்து உருவாக்குகிறது:

from dataclasses import dataclass, field

@dataclass
class Expense:
    title: str
    amount: float
    tags: list[str] = field(default_factory=list)

    def __post_init__(self):
        if self.amount < 0:
            raise ValueError("தொகை எதிர்மறையாக இருக்க முடியாது")

e = Expense("காபி", 250)
print(e)                           # Expense(title='காபி', amount=250, tags=[])
print(e == Expense("காபி", 250))   # True

__init__-இல் முன்பு எழுதிய மதிப்பு சரிபார்ப்பு இப்போது __post_init__-இல் செல்கிறது — அது உருவாக்கப்பட்ட துவக்கிக்குப் பின் உடனே அழைக்கப்படுகிறது. மாற்றக்கூடிய இயல்பு மதிப்புகளை field(default_factory=list) மூலம் மட்டுமே தர வேண்டும்: tags: list = [] என்பதை dataclass தடுத்து ValueError தரும்.

frozen மற்றும் slots

frozen=True பொருளை மாற்ற முடியாததாக்குகிறது; slots=True (Python 3.10 முதல்) __slots__-ஐ உருவாக்கி நினைவகத்தை மிச்சப்படுத்துகிறது. உறைந்த பொருளின் புலத்தை மாற்ற முயன்றால் FrozenInstanceError வரும். புதிய மதிப்புடன் பொருள் வேண்டுமென்றால் நகலை உருவாக்குங்கள்:

from dataclasses import dataclass, replace

@dataclass(frozen=True, slots=True)
class Expense:
    title: str
    amount: float

e = Expense("காபி", 250)
# e.amount = 300   -> dataclasses.FrozenInstanceError
e2 = replace(e, amount=300)
print(e, e2)   # Expense(title='காபி', amount=250) Expense(title='காபி', amount=300)

Python 3.13-இலிருந்து அதே வேலையை பொதுவான copy.replace() செயல்பாடும் செய்யும். உறைந்த dataclass பொருள்களை set-களில் வைக்கலாம், அகராதியின் விசைகளாகவும் பயன்படுத்தலாம் — அவற்றுக்கு __hash__ உண்டு.

வகுப்புகளில் புதியவை: Self, @override, __slots__

வகுப்புகளின் வகை குறிப்புக்கு இரண்டு பயனுள்ள கருவிகள் உள்ளன. typing.Self (Python 3.11, PEP 673) "அதே வகுப்பின் பொருளே திரும்பும்" என்று பொருள்; இது மரபுரிமை பெற்ற முறைகளிலும் வேலை செய்கிறது. @override அலங்காரி (Python 3.12, PEP 698) பெற்றோரின் முறையை மேலெழுத வேண்டிய முறையைக் குறிக்கிறது: பெயரில் எழுத்துப்பிழை இருந்தால் mypy அல்லது pyright அப்படிப்பட்ட அடிப்படை முறை இல்லை என்று சொல்லும்.

from typing import Self, override

class Report:
    def __init__(self):
        self.rows = []

    def add(self, e) -> Self:
        self.rows.append(e)
        return self              # சங்கிலியாக அழைக்கலாம்

class MonthlyReport(Report):
    @override
    def add(self, e) -> Self:
        return super().add(e)

Python 3.15-இல் ஒரு குறுகிய கட்டுப்பாடு நீக்கப்பட்டது: tuple-இன் துணைவகுப்புகளுக்கு காலியல்லாத __slots__ அனுமதிக்கப்படுகிறது, எந்த வகுப்பின் __slots__-இலும் __dict__ மற்றும் __weakref__ குறிப்பிடலாம். 3.14-இல் tuple வாரிசுக்கு அத்தகைய அறிவிப்பு TypeError: nonempty __slots__ not supported for subtype of 'tuple'-உடன் விழுந்தது.

வகுப்புகளில் பொதுவான தவறுகள்

பிழைஅறிகுறிஎப்படி சரிசெய்வது
முறையில் self மறந்ததுTypeError: ... takes 0 positional arguments but 1 was givenமுறையின் முதல் அளவுரு எப்போதும் self
__init__-இல் self. இல்லாத புலம்மதிப்பு __init__-க்குப் பின் மறைகிறதுself.amount = amount என்று எழுதுங்கள்
வகுப்புப் பண்பாக பட்டியல்தரவு பொருள்களுக்கிடையே "கசிகிறது"பட்டியல்களை __init__-இலோ default_factory-இலோ உருவாக்குங்கள்
super().__init__() இல்லைபெற்றோரின் புலங்களில் AttributeErrorபெற்றோரின் துவக்கியை அழையுங்கள்
பண்பை அடைப்புகளுடன் அழைப்பதுTypeError: 'int' object is not callableபண்பை அடைப்புகள் இல்லாமல் படியுங்கள்: r.total

சுருக்கம்

Python OOP எளிமையாகத் தொடங்குகிறது: வகுப்பு புலங்களையும் முறைகளையும் விவரிக்கிறது, __init__ புலங்களை நிரப்புகிறது, self தற்போதைய பொருளைச் சுட்டுகிறது. மரபுரிமையும் super()-உம் நடத்தையை விரிவாக்க அனுமதிக்கின்றன, சுருக்க வகுப்புகள் இடைமுகத்தை வரையறுக்கின்றன, @property கணக்கிடப்படும் புலங்களைத் தருகிறது. தரவு வகுப்புகளுக்கு @dataclass-ஐ எடுங்கள், ஆழமான படிநிலைகளுக்குப் பதிலாக கூட்டமைப்பைத் தேர்ந்தெடுங்கள். வகுப்புகளும் dataclass-களும் Python பாடநெறியில் செலவுக் கணக்கு எடுத்துக்காட்டில் நடைமுறையில் விளக்கப்பட்டுள்ளன.

அடிக்கடி கேட்கப்படும் கேள்விகள்

வகுப்புக்கும் பொருளுக்கும் Python-இல் என்ன வேறுபாடு?

வகுப்பு வகையின் விவரம்: அதற்கு என்ன புலங்களும் முறைகளும் உள்ளன. பொருள், அல்லது நிகழ்வு, வகுப்பை அழைப்பதால் உருவாகிறது, உதாரணமாக Expense("காபி", 250), அது குறிப்பிட்ட புல மதிப்புகளை வைத்திருக்கும்.

வகுப்பில் __init__ கட்டாயமா?

இல்லை. __init__ அறிவிக்கப்படாவிட்டால் object-இலிருந்து வரும் ஒன்று பயன்படுத்தப்படும்; அது எந்த வாதங்களையும் ஏற்காது. dataclass-இல் அதை அலங்காரி உருவாக்குகிறது.

__str__ மற்றும் __repr__ இடையே வேறுபாடு என்ன?

__repr__ டெவலப்பருக்கும் பிழைதிருத்திக்கும் ஒரே பொருளைக் காட்டும் வடிவம்; __str__ print மற்றும் f-சரங்களில் பயனருக்கான தெளிவான வெளியீடு. __str__ இல்லையென்றால் Python __repr__-ஐப் பயன்படுத்தும்.

dataclass எப்போது, சாதாரண வகுப்பு எப்போது?

வகுப்பு முக்கியமாகத் தரவைச் சேமித்து, தயார் __init__, __repr__ மற்றும் ஒப்பீடு தேவைப்படும்போது dataclass. துவக்கத்தில் சிக்கலான தர்க்கம் இருந்தாலோ நடத்தை தரவை விட முக்கியமாக இருந்தாலோ சாதாரண வகுப்பு வசதியானது.

Python-இல் தனிப்பட்ட புலங்கள் உண்டா?

கண்டிப்பான தனியுரிமை இல்லை. பெயரின் தொடக்கத்தில் ஒரு அடிக்கோடு "வெளி பயன்பாட்டுக்கு அல்ல" என்ற ஒப்பந்தம்; இரண்டு அடிக்கோடுகள் பெயர் திரிபை இயக்குகின்றன, அது வாரிசில் தற்செயலான மேலெழுதலிலிருந்து புலத்தைக் காக்கிறது.

இந்தத் தலைப்பை வீடியோவில் கற்றுக்கொள்ளுங்கள்

“Python 3.15: от новичка до профи” பாடநெறியில் இந்தத் தலைப்பு பயிற்சியுடன் விரிவாக விளக்கப்பட்டுள்ளது.

பாடநெறிக்குச் செல்