Last chance! 50% off DataCamp Premium
Sale ends in
Python को एक शक्तिशाली प्रोग्रामिंग भाषा बनाने वाले कारकों में से एक है इसके magic methods। कुछ Pythonista समूहों में, इनके डबल अंडरस्कोर स्वरूप के कारण इन्हें ‘dunder methods’ भी कहा जाता है।
Python में इनका कार्य ‘operator overloading’ नामक प्रक्रिया को निष्पादित करना है, जिसका सीधा अर्थ है किसी पूर्वपरिभाषित ऑपरेटर को विस्तारित अर्थ देना। दूसरे शब्दों में, ऑपरेटर ओवरलोडिंग का उपयोग हमारी कक्षाओं (classes) में कस्टम व्यवहार जोड़ने के लिए किया जाता है ताकि वे Python के ऑपरेटरों और इन-बिल्ट कार्यक्षमताओं के साथ उपयोग योग्य बनें।
इस लेख में, हम Python magic methods को गहराई से समझेंगे, जिसके तहत हम:
इस ट्यूटोरियल में प्रयुक्त कोड को फॉलो करने के लिए यह DataLab वर्कबुक देखें।
यह समझने से पहले कि magic methods क्या हैं, हमें Python में मेथड और फंक्शन के बीच का अंतर जानना होगा।
Python किसी ऑब्जेक्ट के व्यवहार का निरूपण करने के लिए methods का उपयोग करता है। इस प्रकार, methods किसी ऑब्जेक्ट से संबद्ध होते हैं और उस ऑब्जेक्ट के भीतर मौजूद डेटा पर कुछ ऑपरेशन करते हैं। किसी method की एक और महत्वपूर्ण पहचान self पैरामीटर है, जो हमेशा method को पास किए जाने वाला पहला पैरामीटर होता है।
ध्यान दें: पहले पैरामीटर के रूप में शब्द self होना अनिवार्य नहीं है, लेकिन Pythonistas ने सार्वभौमिक रूप से इसे सर्वोत्तम प्रथा माना है।
# Example of a method
class Human:
# This is a method
def walk(self):
print("I am walking")
Methods उस class पर निर्भर होते हैं जिनसे वे संबद्ध हैं। इसलिए, किसी method को कॉल करने के लिए, डॉट ऑपरेटर से method तक पहुँचने से पहले class का एक instance बनाना आवश्यक है।
# This will work
joe = Human()
joe.walk()
"""
I am walking
"""
# This will throw a NameError
walk()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_153/2327344440.py in <module>
4
5 # This will throw a NameError
----> 6 walk()
NameError: name 'walk' is not defined
दूसरी ओर, एक function अलग होता है: हमें class का instance बनाने की आवश्यकता नहीं होती।
Python functions कोड के ब्लॉक के रूप में परिभाषित चरण होते हैं, जो केवल कॉल किए जाने पर निष्पादित होते हैं। वे किसी भी class ऑब्जेक्ट से स्वतंत्र रूप से परिभाषित होते हैं, यानी उन्हें सीधे उनके नाम से कॉल किया जा सकता है। चूँकि वे किसी class से संबद्ध नहीं हैं, हमें self पैरामीटर पास करने की ज़रूरत नहीं होती – पैरामीटर्स वैकल्पिक होते हैं।
मूल रूप से, एक function बस सुव्यवस्थित निर्देशों का समूह होता है जिसका उपयोग इंटरप्रेटर किसी कार्य को करने के लिए करता है।
# Example of a function
def run():
print("I am running.")
run()
"""
I am running.
"""
हमारे How to call and write functions लेख में विस्तार से बताया गया है कि functions दो प्रकार के होते हैं: बिल्ट-इन और यूज़र-परिभाषित।
कई मायनों में, methods और functions समान हैं - यानी दोनों def स्टेटमेंट से परिभाषित होते हैं। मुख्य अंतर यह है कि methods किसी ऑब्जेक्ट से संबद्ध होते हैं और class के भीतर निहित डेटा पर काम करने के लिए उपयोग किए जाते हैं, जबकि functions स्वतंत्र रूप से परिभाषित होते हैं और प्रोग्राम में कहीं भी नाम से कॉल किए जा सकते हैं।
ट्यूटोरियल की शुरुआत में, हमने बताया था कि डबल अंडरस्कोर स्वरूप के कारण magic methods को dunder methods भी कहा जाता है। हमारा अभिप्राय यह था कि सभी Python magic methods दो अंडरस्कोर से शुरू होते और समाप्त होते हैं।
सबसे प्रसिद्ध magic method __init__ है, जो किसी class को विशिष्ट गुणों (attributes) के साथ इनिशियलाइज़ करने में सक्षम बनाता है।
class Employee:
def __init__(self, name, age, role):
self.name = name
self.age = age
self.role = role
इस class का instance बनाने के लिए, हमें instance के name, age, और role गुणों को निर्दिष्ट करना होगा। उदाहरण के लिए:
user_1 = Employee(name="John", age=24, role="Data Scientist")
ऐसा न करने पर TypeError उत्पन्न होगी।
__init__ method इनिशियलाइज़ेशन और कंस्ट्रक्शन magic methods की श्रेणी में आता है, पर यह अकेला नहीं है। नीचे दी गई तालिका में कुछ अन्य इनिशियलाइज़ेशन और कंस्ट्रक्शन magic methods दिए गए हैं।
|
__new__(cls, other) |
किसी class का नया instance बनाने के लिए उपयोग किया जाता है |
|
__init__(self, other) |
नया instance बनने के बाद कॉल होता है; class कंस्ट्रक्टर अभिव्यक्ति को पास किए गए सभी गुण attributes के रूप में उपयोग किए जाएँगे। |
|
__del__(self) |
डिस्ट्रक्टर के रूप में भी जाना जाता है; instance के नष्ट किए जाने पर कॉल होता है। |
Magic methods को समझने का सबसे सरल तरीका यह मानना हो सकता है कि ये आपके इम्प्लीमेंटेशन और Python इंटरप्रेटर के बीच एक अनुबंध हैं। इस अनुबंध की एक शर्त यह है कि कुछ परिस्थितियों में Python पर्दे के पीछे कुछ क्रियाएँ करेगा, जैसे किसी class instance को विशिष्ट ऑब्जेक्ट्स के साथ इनिशियलाइज़ करना।
दूसरे शब्दों में, किसी magic method को सीधे कॉल करना आपकी ज़िम्मेदारी नहीं है - Python इसे पर्दे के पीछे अपने आप निष्पादित करता है।
Python एक ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग (OOP) भाषा है – Python में हर चीज़ एक ऑब्जेक्ट है। जब एक नया ऑब्जेक्ट बनाया जाता है, तो हम अप्रत्यक्ष रूप से एक सम्बद्ध ऑब्जेक्ट भी बनाते हैं क्योंकि सभी classes object से इनहेरिट करती हैं।
टिप्पणी: आप अपने class को परिभाषित करते समय class object पास करके इनहेरिटेंस को स्पष्ट भी कर सकते हैं।
# This works
class Car:
pass
# This also works
class Vehicle(object):
pass
car = Car()
vehicle = Vehicle()
print(car, vehicle, sep="\n")
"""
<__main__.Car object at 0x7f80449dc0a0>
<__main__.Vehicle object at 0x7f80449dc1f0>
"""
ऊपर दिए गए कोड में, हमने दो खाली classes बनाई हैं, फिर भी जब हमने print स्टेटमेंट चलाया, तो Python इंटरप्रेटर को पता था कि क्या प्रिंट करना है। यह संभव है क्योंकि सभी classes object class (Python में सभी classes की पैरेंट) से इनहेरिट करती हैं, और उसमें __repr__ नामक एक magic method होता है, जिसे print स्टेटमेंट वैल्यू लौटाने के लिए कॉल करता है।
जो पाठक इनहेरिटेंस से परिचित हैं, वे जानते होंगे कि एक चाइल्ड class अपने पैरेंट class के method को उसी नाम का अपना method परिभाषित करके ओवरराइड कर सकता है।
# Overriding the object __repr__
class Vehicle:
def __repr__(self):
return f"{self.__class__.__qualname__}"
vehicle = Vehicle()
print(vehicle)
"""
Vehicle
"""
आप __str__ magic method का भी उपयोग कर सकते हैं ताकि print स्टेटमेंट के साथ कॉल होने वाली स्ट्रिंग रिप्रेज़ेंटेशन बनाई जा सके।
वास्तव में, __repr__ magic method, __str__ magic method के बैकअप व्यवहार के रूप में कार्य करता है। इसलिए, जब हम print स्टेटमेंट कॉल करते हैं, तो Python पहले आपकी class में परिभाषित __str__ method को ढूँढता है और उसके न मिलने पर __repr__ method पर वापस जाता है।
# Using __str__ for string representation
class Vehicle:
def __str__(self):
return f"{self.__class__.__qualname__}"
vehicle = Vehicle()
print(vehicle)
"""
Vehicle
"""
नीचे दी गई तालिका में अन्य स्ट्रिंग रिप्रेज़ेंटेशन magic methods की सूची दी गई है।
|
__str__(self) |
Python के इन-बिल्ट str() फंक्शन और print स्टेटमेंट द्वारा किसी ऑब्जेक्ट की अनौपचारिक स्ट्रिंग रिप्रेज़ेंटेशन दिखाने के लिए कॉल किया जाता है। ध्यान दें कि इसके लिए वैध Python अभिव्यक्ति होना आवश्यक नहीं है। |
|
__repr__(self) |
Python के इन-बिल्ट repr() फंक्शन और स्ट्रिंग कन्वर्ज़न द्वारा किसी ऑब्जेक्ट की आधिकारिक स्ट्रिंग रिप्रेज़ेंटेशन दिखाने के लिए कॉल किया जाता है। ध्यान दें कि यह एक वैध Python अभिव्यक्ति जैसा दिखना चाहिए, लेकिन यदि यह संभव न हो तो उपयोगी विवरण वाली स्ट्रिंग को प्राथमिकता दी जाती है। |
|
__unicode__(self) |
Python के इन-बिल्ट unicode() फंक्शन को इम्प्लीमेंट करने के लिए कॉल किया जाता है और यह एक Unicode ऑब्जेक्ट लौटाता है। |
|
__hash__(self) |
Python के इन-बिल्ट hash() फंक्शन और hashed कलेक्शनों के सदस्यों पर किए जाने वाले ऑपरेशंस द्वारा कॉल किया जाता है। यह method एक पूर्णांक लौटाना चाहिए। |
|
__nonzero__(self) |
Python के इन-बिल्ट bool() ऑपरेशन द्वारा सत्यता जाँच (truth value testing) को लागू करने के लिए कॉल किया जाता है। यह method True या False (या उनके पूर्णांक समतुल्य 1 या 0) लौटाना चाहिए। |
एन्कैप्सुलेशन ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग (OOP) की मूलभूत अवधारणाओं में से एक है। यह डेटा और उस डेटा पर काम करने वाले methods को एक साथ बाँधने या किसी ऑब्जेक्ट के भीतर कुछ कॉम्पोनेन्ट्स तक सीधे एक्सेस को प्रतिबंधित करने को संदर्भित करता है।
अन्य OOP भाषाओं से आने वाले डेवलपर्स अक्सर यह तर्क देते हैं कि Python कक्षाओं के लिए एन्कैप्सुलेशन को सच में अपनाने में असफल रहा है। ये लोग methods या फ़ील्ड्स के लिए स्पष्ट मॉडिफ़ायर्स के आदी होते हैं जो उन्हें पब्लिक गेटर्स और सेटर्स के साथ प्राइवेट एट्रिब्यूट्स जैसी चीज़ें परिभाषित करने में सक्षम बनाते हैं। Python में अंतर यह है कि एन्कैप्सुलेशन का बहुत सा भाग magic methods के माध्यम से होता है।
उदाहरण के लिए, __setattr__ एक एन्कैप्सुलेशन समाधान है जो हमें किसी एट्रिब्यूट को असाइन करते समय (चाहे वह मौजूद हो या नहीं) व्यवहार परिभाषित करने में सक्षम बनाता है। दूसरे शब्दों में, एट्रिब्यूट्स के मानों में बदलाव के लिए नियम परिभाषित किए जा सकते हैं।
import string
class Alphabet():
def __setattr__(self, name, value):
self.__dict__[name] = value.upper()
a = Alphabet()
# Assinging an attribute that does not exist
# The setattr should convert it to caps despite being set as lowercase
a.alphabet = string.ascii_lowercase
print(a.alphabet)
ऊपर दिए गए कोड में, हमने Alphabet नामक एक class बनाई जिसके कोई एट्रिब्यूट्स नहीं हैं, लेकिन हमने Python को यह बताया कि class instance के किसी भी एट्रिब्यूट को सेट करते समय उसे कैपिटल में बदलना है।
हम समझते हैं कि कुछ पाठकों के लिए OOP थोड़ी दूर की चीज़ हो सकती है। Python में OOP पर पकड़ मज़बूत करने के लिए DataCamp का Python Programmer Track देखें।
Python magic methods की एक और श्रेणी गणितीय magic methods हैं (जिन्हें सामान्य arithmetic ऑपरेटर्स भी कहा जाता है)। Python में अभिव्यक्तियाँ विशेष प्रतीकों, यानी ‘ऑपरेटर्स’ का उपयोग करके बनाई जाती हैं। किसी अभिव्यक्ति में ऐसे ऑपरेटर्स का उपयोग करने का अर्थ उन ऑब्जेक्ट्स का निर्माण करना है जिनमें संबंधित math magic methods हों। ऐसा न करने पर TypeError उत्पन्न होगी।
class Numbers:
def __init__(self, a, b):
self.a = a
self.b = b
set_a = Numbers(2, 4)
set_b = Numbers(3, 5)
print(set_a + set_b)
"""
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/tmp/ipykernel_152/3639634723.py in <module>
7 set_b = Numbers(3, 5)
8
----> 9 print(set_a + set_b)
TypeError: unsupported operand type(s) for +: 'Numbers' and 'Numbers'
"""
ऊपर दिए गए कोड में, हमने Numbers class के कई instances बनाने और उन्हें आपस में जोड़ने का प्रयास किया, जिससे अपेक्षित रूप से त्रुटि आई। इस त्रुटि का एक समाधान यह हो सकता है कि हम अपनी class में नंबर जोड़ने के लिए कोई method बनाएँ, लेकिन इससे हम अभिव्यक्तियाँ (expressions) बनाने से वंचित रहेंगे।
एक बेहतर समाधान __add__ magic method को निम्नानुसार इम्प्लीमेंट करना होगा:
# Using add operator
class Numbers:
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
# Only permit Numbers objects to be added
if not isinstance(other, Numbers):
return NotImplemented
return Numbers(other.a + self.a, other.b + self.b)
def __repr__(self):
return f"{self.__class__.__qualname__}({self.a}, {self.b})"
a = Numbers(2, 4)
b = Numbers(3, 5)
print(a + b) # Should result in Numbers(5, 9)
"""
RandomNumbers(5, 9)
"""
ऊपर दिए गए कोड उदाहरण में हम केवल दो Numbers ऑब्जेक्ट्स को आपस में जोड़ सकते हैं। आइए एक और math magic method इम्प्लीमेंट करें जो हमें किसी Numbers ऑब्जेक्ट को एक पूर्णांक से गुणा करने की अनुमति दे।
# Multiplying Numbers with an integer
class Numbers:
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
# Only permit Numbers objects to be added
if not isinstance(other, Numbers):
return NotImplemented
return Numbers(other.a + self.a, other.b + self.b)
def __mul__(self, other):
if not isinstance(other, int):
return NotImplemented
return Numbers(self.a * other, self.b * other)
def __repr__(self):
return f"{self.__class__.__qualname__}({self.a}, {self.b})"
a = Numbers(2, 4)
print(a * 5) # Should return 10, 20
"""
RandomNumbers(10, 20)
"""
ऊपर दिए गए कोड में, हमने __mul__ magic method जोड़ा ताकि हम अपनी कस्टम class के नंबरों को किसी पूर्णांक से गुणा कर सकें।
ध्यान दें कि Numbers ऑब्जेक्ट * ऑपरेटर के बाएँ तरफ है - यह संयोग नहीं है। आइए इसे ऑपरेटर के दाएँ तरफ रखें और देखें क्या होता है।
- snip --
a = Numbers(2, 4)
print(3 * a)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/tmp/ipykernel_152/2857655049.py in <module>
1 a = Numbers(2, 4)
----> 2 print(3 * a)
TypeError: unsupported operand type(s) for *: 'int' and 'Numbers'
Python एक TypeError फेंकता है।
हमारे द्वारा इम्प्लीमेंट किया गया __mul__ magic method केवल तब काम करता है जब Numbers ऑब्जेक्ट * ऑपरेटर के बाएँ हाथ की ओर हो। इस कार्यक्षमता का विस्तार करने के लिए, हमें रिवर्स magic method __rmul__ जोड़ना होगा।
# Enabling reverse multiplication
class Numbers:
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
# Only permit Numbers objects to be added
if not isinstance(other, Numbers):
return NotImplemented
return Numbers(other.a + self.a, other.b + self.b)
def __mul__(self, other):
if not isinstance(other, int):
return NotImplemented
return Numbers(self.a * other, self.b * other)
def __rmul__(self, other):
return self.__mul__(other)
def __repr__(self):
return f"{self.__class__.__qualname__}({self.a}, {self.b})"
a = Numbers(2, 4)
print(5 * a) # Should return 10, 20
"""
Numbers(10, 20)
"""
अब हम गुणा करने वाली अभिव्यक्ति बना सकते हैं, बिना इस पर विचार किए कि Numbers ऑब्जेक्ट ऑपरेटर के किस तरफ है।
Python magic methods का लाभ उठाने का मूल सिद्धांत समान रहता है: एक class बनाएँ और object class के magic method को ओवरराइड करें। Python में इतने अधिक magic methods हैं कि अगर हम सभी को अलग-अलग कवर करें तो यह ट्यूटोरियल अत्यधिक लंबा हो जाएगा। हम अत्यधिक अनुशंसा करते हैं कि आप Python प्रलेखन देखें ताकि आपको उन सभी Python magic methods का अंदाज़ा हो सके जिन्हें आप अपनी Python प्रोग्रामिंग स्किल्स को निखारने के लिए उपयोग कर सकते हैं।
Python के लिए पाठ्यक्रम
कोर्स
कोर्स
कोर्स