क्लासेस और ऑब्जेक्ट्स
अब तक आपने जिन भी टाइप्स के साथ काम किया है (स्ट्रिंग्स, लिस्ट्स, डिक्शनरीज़) वे वास्तव में क्लासेस हैं। जब आप "hello".upper() कॉल करते हैं, तो आप एक स्ट्रिंग ऑब्जेक्ट पर एक मेथड कॉल कर रहे होते हैं। क्लासेस आपको अपने स्वयं के डेटा और व्यवहार के साथ अपने स्वयं के टाइप्स परिभाषित करने देती हैं। एक Player क्लास एक नाम, स्कोर और लेवल रख सकती है, और जान सकती है कि स्वयं को कैसे प्रदर्शित करना है।
ब्लूप्रिंट और इंस्टेंसेस
एक क्लास एक ब्लूप्रिंट है। एक इंस्टेंस उस ब्लूप्रिंट से बनी एक विशिष्ट चीज़ है। आप जितने चाहें उतने इंस्टेंस बना सकते हैं, प्रत्येक के अपने डेटा के साथ लेकिन क्लास में परिभाषित समान मेथड्स को साझा करते हुए।
class Dog:
def bark(self):
print("Woof!")
rex = Dog()
luna = Dog()
rex.bark() # "Woof!"
luna.bark() # "Woof!"Dog क्लास है। rex और luna इंस्टेंसेस हैं: दो अलग-अलग कुत्ते, प्रत्येक क्लास में परिभाषित समान व्यवहार साझा करते हुए।
__init__ और self
__init__ वह मेथड है जिसे Python तब स्वचालित रूप से कॉल करता है जब आप एक नया इंस्टेंस बनाते हैं। यह वह जगह है जहाँ आप ऑब्जेक्ट के लिए शुरुआती डेटा सेट करते हैं। self वह तरीका है जिससे एक मेथड उस विशिष्ट इंस्टेंस को संदर्भित करता है जिस पर वह कार्य कर रहा है, और यह हमेशा पहला पैरामीटर होता है।
class Player:
def __init__(self, name, score=0):
self.name = name
self.score = score
def add_points(self, points):
self.score += points
def display(self):
print(f"{self.name}: {self.score} points")
alice = Player("आरव")
bob = Player("दीया", score=50)
alice.add_points(30)
alice.display() # "आरव: 30 points"
bob.display() # "दीया: 50 points"self.name और self.score इंस्टेंस एट्रिब्यूट्स हैं: वे विशिष्ट ऑब्जेक्ट से संबंधित हैं, स्वयं क्लास से नहीं। प्रत्येक Player इंस्टेंस का अपना name और score होता है।
मेथड्स
एक क्लास के अंदर परिभाषित कोई भी फ़ंक्शन एक मेथड है। इंस्टेंस मेथड्स में हमेशा पहले पैरामीटर के रूप में self होता है; Python इसे स्वचालित रूप से पास करता है। मेथड्स self के माध्यम से इंस्टेंस के डेटा को पढ़ और बदल सकते हैं।
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
def scale(self, factor):
self.radius *= factor
return self # self लौटाने से चेनिंग की अनुमति मिलती है: c.scale(2).scale(0.5)
c = Circle(5)
print(c.area()) # 78.53975
c.scale(2)
print(c.area()) # 314.159क्लास वैरिएबल्स बनाम इंस्टेंस वैरिएबल्स
सीधे क्लास पर परिभाषित वैरिएबल्स (न कि __init__ के अंदर) क्लास वैरिएबल्स हैं। सभी इंस्टेंसेस एक ही क्लास वैरिएबल साझा करते हैं। __init__ के अंदर self पर सेट किए गए वैरिएबल्स इंस्टेंस वैरिएबल्स हैं, जो प्रत्येक ऑब्जेक्ट के लिए अनूठे हैं।
class Player:
max_lives = 3 # क्लास वैरिएबल, हर Player के लिए समान
def __init__(self, name):
self.name = name # इंस्टेंस वैरिएबल, प्रत्येक Player के लिए अनूठा
self.lives = Player.max_lives
def die(self):
self.lives -= 1
alice = Player("आरव")
bob = Player("दीया")
Player.max_lives = 5 # सभी वर्तमान और भविष्य के इंस्टेंसेस के लिए बदलेंसभी इंस्टेंसेस में साझा मानों के लिए क्लास वैरिएबल्स का उपयोग करें: कॉन्स्टैंट्स, काउंटर्स, डिफ़ॉल्ट्स। उस डेटा के लिए इंस्टेंस वैरिएबल्स का उपयोग करें जो प्रति ऑब्जेक्ट भिन्न होता है।
__str__ और __repr__
__str__ नियंत्रित करता है कि print() और f-स्ट्रिंग्स आपके ऑब्जेक्ट के लिए क्या दिखाते हैं। __repr__ कंसोल में और डिबगिंग के लिए दिखाए जाने वाले डेवलपर व्यू को नियंत्रित करता है। हमेशा __repr__ परिभाषित करें। __str__ तब परिभाषित करें जब आप डिबग व्यू से अलग एक स्वच्छ यूज़र-फेसिंग प्रदर्शन चाहते हैं।
class Player:
def __init__(self, name, score):
self.name = name
self.score = score
def __str__(self):
return f"{self.name} ({self.score} pts)"
def __repr__(self):
return f"Player(name={self.name!r}, score={self.score})"
alice = Player("आरव", 87)
print(alice) # "आरव (87 pts)" (__str__ का उपयोग करता है)
repr(alice) # "Player(name='आरव', score=87)" (__repr__ का उपयोग करता है)हमेशा __repr__ परिभाषित करें। __str__ तब परिभाषित करें जब आप डिबग व्यू से अलग एक स्वच्छ यूज़र-फेसिंग प्रतिनिधित्व चाहते हैं। यदि केवल __repr__ परिभाषित है, तो Python इसे दोनों के लिए उपयोग करता है।
प्राइवेट परंपरा
Python में वास्तव में प्राइवेट वैरिएबल्स नहीं हैं, लेकिन एक नाम की शुरुआत में एक एकल अंडरस्कोर (_balance) एक परंपरा है जो संकेत देता है "यह आंतरिक है, इसे क्लास के बाहर से सीधे उपयोग न करें"। यह भाषा द्वारा लागू नहीं किया जाता है; यह अन्य डेवलपर्स के लिए एक संचार है।
class BankAccount:
def __init__(self, balance):
self._balance = balance # _ का अर्थ है "हाथ हटाओ"
def deposit(self, amount):
if amount > 0:
self._balance += amount
def balance(self):
return self._balanceएक दोहरा अंडरस्कोर (__name) नेम मैंगलिंग ट्रिगर करता है; Python सबक्लासेस में टकराव से बचने के लिए एट्रिब्यूट का नाम बदलकर _ClassName__name कर देता है। इसकी शायद ही कभी आवश्यकता होती है। एकल अंडरस्कोर अधिकांश कोड में परंपरा है।
इनहेरिटेंस
एक क्लास दूसरी क्लास से इनहेरिट कर सकती है, अपने आप उसके सभी एट्रिब्यूट्स और मेथड्स प्राप्त कर सकती है। फिर आप उनके व्यवहार को बदलने के लिए सबक्लास में विशिष्ट मेथड्स को ओवरराइड कर सकते हैं। यह आपको एक सामान्य आधार का पुन: उपयोग करने और जहाँ आवश्यक हो वहाँ विशेषीकरण करने देता है।
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "..."
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
pets = [Dog("रेक्स"), Cat("लूना"), Dog("मैक्स")]
for pet in pets:
print(pet.speak())Dog और Cat Animal से __init__ इनहेरिट करते हैं, इसलिए उन्हें अपने स्वयं की आवश्यकता नहीं है। वे अपने विशिष्ट व्यवहार के साथ speak() को ओवरराइड करते हैं।
super()
super() पैरेंट क्लास से एक मेथड कॉल करता है। इसका उपयोग तब करें जब आप पैरेंट के व्यवहार को पूरी तरह से बदलने के बजाय विस्तारित करना चाहते हैं: इसके सेटअप को चलाने के लिए पैरेंट के __init__ को कॉल करें, फिर अपने सबक्लास को जो कुछ भी ऊपर चाहिए वह जोड़ें।
class Animal:
def __init__(self, name, sound):
self.name = name
self.sound = sound
class Dog(Animal):
def __init__(self, name):
super().__init__(name, "Woof") # Animal.__init__ कॉल करें
self.tricks = [] # कुछ अतिरिक्त जोड़ें
def learn(self, trick):
self.tricks.append(trick)
rex = Dog("रेक्स")
rex.learn("sit")
print(rex.tricks) # ["sit"]हमेशा super().__init__() कॉल करें जब आपके सबक्लास का अपना __init__ हो और पैरेंट का भी हो।
क्लास मेथड्स और स्टैटिक मेथड्स
@classmethod एक ऐसा मेथड बनाता है जो एक इंस्टेंस के बजाय स्वयं क्लास को प्राप्त करता है। यह वैकल्पिक कंस्ट्रक्टर्स के लिए उपयोगी है: स्ट्रिंग, फ़ाइल या किसी अन्य प्रारूप से एक इंस्टेंस बनाना। @staticmethod एक साधारण फ़ंक्शन है जो संगठनात्मक कारणों से क्लास के अंदर रहता है; यह न तो इंस्टेंस और न ही क्लास को प्राप्त करता है।
class Player:
def __init__(self, name, score):
self.name = name
self.score = score
@classmethod
def from_string(cls, data):
name, score = data.split(",")
return cls(name, int(score))
alice = Player.from_string("आरव,87")class Player:
@staticmethod
def is_valid_name(name):
return name.isalpha() and len(name) >= 2
Player.is_valid_name("आरव") # True
Player.is_valid_name("A1") # Falseवैकल्पिक कंस्ट्रक्टर्स के लिए @classmethod का उपयोग करें। यूटिलिटी फ़ंक्शंस के लिए @staticmethod का उपयोग करें जो तार्किक रूप से क्लास के साथ हैं लेकिन इंस्टेंस या क्लास डेटा की आवश्यकता नहीं है।
@property
@property आपको एक मेथड को एक एट्रिब्यूट की तरह एक्सेस करने देता है, बिना कोष्ठक की आवश्यकता के। उन मानों के लिए इसका उपयोग करें जो अन्य एट्रिब्यूट्स से गणना किए जाते हैं और सरल एट्रिब्यूट एक्सेस के रूप में पढ़ने में स्वाभाविक लगते हैं।
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14159 * self.radius ** 2
@property
def diameter(self):
return self.radius * 2
c = Circle(5)
print(c.area) # 78.53975 (एक एट्रिब्यूट की तरह दिखता है, एक मेथड की तरह चलता है)
print(c.diameter) # 10प्रॉपर्टीज़ गणना किए गए मानों के लिए उपयोगी हैं: अन्य एट्रिब्यूट्स से प्राप्त चीज़ें जिन्हें () के बिना एक्सेस करना स्वाभाविक लगता है।
व्यवहार में
इंस्टेंस एट्रिब्यूट्स, मेथड्स, एक @property, और __str__ के साथ एक Player क्लास:
class Player:
max_lives = 3
def __init__(self, name: str):
self.name = name
self.score = 0
self.lives = Player.max_lives
def earn_points(self, amount: int) -> None:
self.score += amount
def take_hit(self) -> bool:
self.lives -= 1
return self.lives > 0
@property
def is_alive(self) -> bool:
return self.lives > 0
def __str__(self) -> str:
return f"{self.name} | Score: {self.score} | Lives: {self.lives}"
alice = Player("आरव")
alice.earn_points(50)
alice.take_hit()
print(alice) # "आरव | Score: 50 | Lives: 2"
print(alice.is_alive) # True
