पायथन 'जादू के तरीकों' का उपयोग क्यों करता है?


99

मैं हाल ही में पायथन के साथ खेल रहा हूं, और एक चीज जो मुझे थोड़ी अजीब लग रही है, वह है 'मैजिक मेथड्स' का व्यापक उपयोग, उदाहरण के लिए इसकी लंबाई उपलब्ध कराने के लिए, एक ऑब्जेक्ट एक विधि को लागू करता है def __len__(self), और फिर इसे तब कहा जाता है जब आप लिखते हैं len(obj)

मैं बस सोच रहा था कि वस्तुएं बस एक len(self)विधि को परिभाषित क्यों नहीं करती हैं और इसे सीधे वस्तु के सदस्य के रूप में कहा जाता है, जैसे obj.len()? मुझे यकीन है कि पायथन के लिए इसे करने के अच्छे कारण होने चाहिए, लेकिन यह एक नौसिखिया के रूप में मैंने अभी तक काम नहीं किया है।


4
मुझे लगता है कि सामान्य कारण ए) ऐतिहासिक और बी) कुछ है len()या reversed()कई प्रकार की वस्तुओं पर लागू होता है, लेकिन एक विधि जैसे कि append()केवल अनुक्रमों पर लागू होती है, आदि
अनुदान पॉल

जवाबों:


64

AFAIK, lenइस संबंध में विशेष है और इसकी ऐतिहासिक जड़ें हैं।

यहाँ FAQ से एक उद्धरण है :

पायथन कुछ कार्यक्षमता के लिए तरीकों का उपयोग क्यों करता है (जैसे सूची.इंडेक्स ()) लेकिन अन्य के लिए कार्य करता है (जैसे लेन (सूची))?

इसकी बड़ी वजह इतिहास है। उन कार्यों के लिए फ़ंक्शंस का उपयोग किया गया था जो प्रकार के समूह के लिए सामान्य थे और जिनका उद्देश्य उन वस्तुओं के लिए भी काम करना था जिनके पास बिल्कुल भी तरीके नहीं थे (उदाहरण के लिए ट्यूल)। जब आप पायथन (मानचित्र) (लागू), () एट अल) के कार्यात्मक सुविधाओं का उपयोग करते हैं, तो यह एक फ़ंक्शन के लिए भी सुविधाजनक है जो वस्तुओं के अनाकार संग्रह पर आसानी से लागू हो सकता है।

वास्तव में, अंतर्निहित फ़ंक्शन के रूप में लेन (), अधिकतम (), मिनट () को लागू करना वास्तव में प्रत्येक प्रकार के तरीकों के रूप में उन्हें लागू करने की तुलना में कम कोड है। कोई व्यक्ति व्यक्तिगत मामलों के बारे में विचार कर सकता है, लेकिन यह पायथन का एक हिस्सा है, और अब इस तरह के मूलभूत परिवर्तन करने में बहुत देर हो चुकी है। बड़े पैमाने पर कोड टूटने से बचने के लिए कार्यों को करना पड़ता है।

अन्य "जादुई तरीके" (वास्तव में पायथन लोककथाओं में विशेष विधि कहा जाता है) बहुत सारे अर्थ बनाते हैं, और इसी तरह की कार्यक्षमता अन्य भाषाओं में मौजूद है। वे ज्यादातर कोड के लिए उपयोग किए जाते हैं जो विशेष रूप से सिंटैक्स का उपयोग किए जाने पर निहित कहलाते हैं।

उदाहरण के लिए:

  • अतिभारित ऑपरेटर (C ++ और अन्य में मौजूद)
  • निर्माता / नाशक
  • विशेषताओं तक पहुँचने के लिए हुक
  • मेटाप्रोग्रामिंग के लिए उपकरण

और इसी तरह...


2
पायथन और प्रिंसिपल ऑफ़ लिस्ट एस्टनिशन कुछ फायदे के लिए पायथन को इस तरह से पढ़ा जा रहा है (हालांकि मैं अंग्रेजी जरूरतों के काम को स्वीकार करता हूं)। मूल बिंदु: यह मानक लाइब्रेरी को एक टन कोड को लागू करने की अनुमति देता है जो बहुत, बहुत पुन: प्रयोज्य लेकिन अभी भी अधिक उपयोग योग्य हो जाता है।
jpmc26

20

पायथन के ज़ेन से:

अस्पष्टता के सामने, अनुमान लगाने के प्रलोभन से इनकार करें।
वहाँ एक होना चाहिए - और अधिमानतः यह करने के लिए केवल एक ही - स्पष्ट तरीका।

यह एक कारण है - कस्टम तरीकों के साथ, डेवलपर्स एक भिन्न तरीके से नाम, जैसे चुनने के लिए स्वतंत्र होगा getLength(), length(), getlength()या जो भी। पायथन सख्त नामकरण को लागू करता है ताकि आम फ़ंक्शन len()का उपयोग किया जा सके।

सभी प्रकार के ऑब्जेक्ट्स के लिए सभी ऑपरेशन सामान्य होते हैं, जैसे जादू के तरीकों में __nonzero__, __len__या __repr__। वे ज्यादातर वैकल्पिक हैं, हालांकि।

ऑपरेटर ओवरलोडिंग भी जादू के तरीकों (जैसे __le__) के साथ किया जाता है , इसलिए यह उन्हें अन्य सामान्य कार्यों के लिए भी उपयोग करने के लिए समझ में आता है।


यह एक सम्मोहक तर्क है। अधिक संतोषजनक है कि "गुइडो वास्तव में OO में विश्वास नहीं करता था" .... (जैसा कि मैंने कहीं और दावा किया है)।
एंडी हेडन

15

पायथन शब्द "मैजिक मेथड्स" का उपयोग करता है , क्योंकि वे तरीके वास्तव में आपके लिए जादू का काम करते हैं। पायथन के जादू के तरीकों का उपयोग करने का एक सबसे बड़ा लाभ यह है कि वे वस्तुओं को बिल्ट-इन प्रकारों की तरह व्यवहार करने का एक सरल तरीका प्रदान करते हैं। इसका मतलब है कि आप बुनियादी ऑपरेटरों के प्रदर्शन के बदसूरत, प्रति-सहज ज्ञान युक्त और गैर-मानक तरीकों से बच सकते हैं।

एक निम्नलिखित उदाहरण पर विचार करें:

dict1 = {1 : "ABC"}
dict2 = {2 : "EFG"}

dict1 + dict2
Traceback (most recent call last):
  File "python", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict' and 'dict'

यह एक त्रुटि देता है, क्योंकि शब्दकोश प्रकार इसके अतिरिक्त समर्थन नहीं करता है। अब, शब्दकोश कक्षा का विस्तार करते हैं और "__add__" जादू विधि जोड़ते हैं :

class AddableDict(dict):

    def __add__(self, otherObj):
        self.update(otherObj)
        return AddableDict(self)


dict1 = AddableDict({1 : "ABC"})
dict2 = AddableDict({2 : "EFG"})

print (dict1 + dict2)

अब, यह निम्नलिखित आउटपुट देता है।

{1: 'ABC', 2: 'EFG'}

इस प्रकार, इस पद्धति को जोड़कर, अचानक जादू हो गया है और जो त्रुटि आपको पहले मिल रही थी, वह दूर हो गई है।

मुझे उम्मीद है, यह आपके लिए चीजों को स्पष्ट करता है। अधिक जानकारी के लिए, यहां देखें:

पायथन के मैजिक मेथड्स के लिए एक गाइड (कैफे केटलर, 2012)


9

इनमें से कुछ कार्य एक से अधिक तरीकों को लागू करने में सक्षम होंगे (बिना सुपरक्लास के अमूर्त तरीकों के बिना)। उदाहरण के लिए bool()इस तरह का कार्य करता है:

def bool(obj):
    if hasattr(obj, '__nonzero__'):
        return bool(obj.__nonzero__())
    elif hasattr(obj, '__len__'):
        if obj.__len__():
            return True
        else:
            return False
    return True

आप यह भी 100% सुनिश्चित कर सकते हैं कि bool()हमेशा सही या गलत लौटेगा; यदि आप एक विधि पर भरोसा करते हैं तो आप पूरी तरह से निश्चित नहीं हो सकते कि आपको क्या मिलेगा।

कुछ अन्य कार्यों में अपेक्षाकृत जटिल कार्यान्वयन होते हैं (अंतर्निहित जादू विधियों की तुलना में अधिक जटिल होने की संभावना है) iter()और cmp(), और सभी विशेषता विधियां ( और getattr, ) हैं। ज़बरदस्ती करते समय (जैसे आप लागू कर सकते हैं ) मैजिक मेथड्स जैसी चीजें भी एक्सेस करते हैं , लेकिन टाइप के रूप में डबल ड्यूटी करते हैं। वास्तव में एक मामला है जहाँ मुझे विश्वास नहीं होता कि यह कभी इससे अलग है ।setattrdelattrint__int__len(obj)obj.__len__()


2
इसके बजाय hasattr()मैं का उपयोग करेगा try:/ except AttributeError:और बजाय if obj.__len__(): return True else: return Falseमैं सिर्फ कहना होगा, return obj.__len__() > 0लेकिन वे सिर्फ शैलीगत चीजें हैं।
क्रिस लुत्ज़

अजगर 2.6 (जो btw के लिए bool(x)भेजा गया है x.__nonzero__()) में, आपका तरीका काम नहीं करेगा। बूल उदाहरणों में एक विधि है __nonzero__(), और आपका कोड एक बार obj एक बूल होने पर खुद को कॉल करता रहेगा। शायद bool(obj.__bool__())उसी तरह से व्यवहार किया जाना चाहिए जिस तरह से आपने इलाज किया था __len__? (या यह कोड वास्तव में पायथन 3 के लिए काम करता है?)
पोंकाडूडल

बूल की परिपत्र प्रकृति () कुछ हद तक जानबूझकर बेतुकी थी, परिभाषा की ख़ासकर परिपत्र प्रकृति को प्रतिबिंबित करने के लिए। एक तर्क है कि इसे केवल एक आदिम माना जाना चाहिए।
इयान बेकिंग

एकमात्र अंतर (वर्तमान में) है len(x)और x.__len__()यह है कि पूर्व अधिक से अधिक लंबाई के लिए अतिप्रवाह करेगा sys.maxsize, जबकि बाद वाला आमतौर पर पायथन में लागू किए गए प्रकारों के लिए नहीं होगा। यह एक विशेषता से अधिक बग है, हालांकि (जैसे कि पायथन 3.2 की रेंज ऑब्जेक्ट ज्यादातर मनमाने ढंग से बड़ी रेंज को संभाल सकती है, लेकिन lenउनके साथ उपयोग करना विफल हो सकता है। __len__हालांकि, वे विफल होते हैं, हालांकि वे पायथन के बजाय सी में लागू होते हैं)
ncogolan

4

वे वास्तव में "जादू के नाम" नहीं हैं। यह सिर्फ इंटरफ़ेस है जो एक वस्तु को दी गई सेवा प्रदान करने के लिए लागू करना है। इस अर्थ में, वे किसी भी पूर्वनिर्धारित इंटरफ़ेस परिभाषा से अधिक जादू नहीं हैं जिसे आपको फिर से लागू करना है।


1

जबकि कारण ज्यादातर ऐतिहासिक है, पायथन में कुछ ख़ासियतें हैं lenजो एक विधि के बजाय एक फ़ंक्शन का उपयोग उचित बनाती हैं।

अजगर में कुछ कार्यों के तरीकों, उदाहरण के लिए के रूप में लागू किया जाता है list.indexऔर dict.append, जबकि दूसरों को, callables और जादू तरीके के रूप में लागू किया जाता है, उदाहरण के लिए strऔर iterऔर reversed। दोनों समूह अलग-अलग हैं इसलिए अलग दृष्टिकोण उचित है:

  1. वे आम हैं।
  2. str, intऔर मित्र प्रकार हैं। यह कंस्ट्रक्टर को कॉल करने के लिए अधिक समझ में आता है।
  3. कार्यान्वयन फ़ंक्शन कॉल से भिन्न होता है। उदाहरण के लिए, iterकॉल कर सकते हैं __getitem__, तो __iter__उपलब्ध नहीं है, और अतिरिक्त तर्क है कि एक विधि कॉल में फिट नहीं है समर्थन करता है। इसी कारण से पायथन के हाल के संस्करणों में it.next()बदल दिया गया है next(it)- यह अधिक समझ में आता है।
  4. इनमें से कुछ ऑपरेटरों के करीबी रिश्तेदार हैं। कॉलिंग के लिए वाक्यविन्यास है __iter__और __next__इसे forलूप कहा जाता है । स्थिरता के लिए, एक फ़ंक्शन बेहतर है। और यह कुछ अनुकूलन के लिए बेहतर बनाता है।
  5. कुछ कार्य बस किसी तरह से बाकी के समान हैं - reprजैसे कार्य strकरता है। बीत रहा है str(x)बनाम x.repr()भ्रामक होगा।
  6. उनमें से कुछ शायद ही कभी वास्तविक कार्यान्वयन विधि का उपयोग करते हैं, उदाहरण के लिए isinstance
  7. उनमें से कुछ वास्तविक ऑपरेटर हैं, करने getattr(x, 'a')का एक और तरीका है x.aऔर getattrउपरोक्त गुणों में से कई को साझा करता है।

मैं व्यक्तिगत रूप से पहले समूह की पद्धति और दूसरे समूह के ऑपरेटर की तरह कहता हूं। यह बहुत अच्छा अंतर नहीं है, लेकिन मुझे उम्मीद है कि यह किसी भी तरह से मदद करेगा।

यह कहने के बाद, lenदूसरे समूह में बिल्कुल फिट नहीं है। यह पहले एक में परिचालन के अधिक करीब है, एकमात्र अंतर है कि यह लगभग किसी भी तरह से अधिक सामान्य है। लेकिन केवल एक चीज जो यह करती है वह है कॉलिंग __len__, और यह बहुत करीब है L.index। हालाँकि, कुछ अंतर हैं। उदाहरण के लिए, __len__अन्य विशेषताओं के कार्यान्वयन के लिए बुलाया जा सकता है, जैसे कि bool, यदि विधि को कहा जाता है lenतो आप bool(x)कस्टम lenविधि से टूट सकते हैं जो पूरी तरह से अलग चीज है।

संक्षेप में, आपके पास बहुत ही सामान्य विशेषताओं का एक सेट है जो कक्षाएं लागू कर सकती हैं जिन्हें एक विशेष फ़ंक्शन के माध्यम से ऑपरेटर के माध्यम से एक्सेस किया जा सकता है (जो आमतौर पर एक ऑपरेटर के रूप में कार्यान्वयन से अधिक होता है), ऑब्जेक्ट निर्माण के दौरान, और उन सभी को। कुछ सामान्य लक्षण साझा करें। बाकी सब एक विधि है। और lenकुछ हद तक उस नियम का अपवाद है।


0

उपरोक्त दो पदों को जोड़ने के लिए बहुत कुछ नहीं है, लेकिन सभी "जादू" फ़ंक्शन वास्तव में बिल्कुल भी जादू नहीं हैं। वे __ buildins__ मॉड्यूल का हिस्सा होते हैं जो दुभाषिया शुरू होने पर अंतर्निहित / स्वचालित रूप से आयात किया जाता है। अर्थात:

from __builtins__ import *

आपका कार्यक्रम शुरू होने से पहले हर बार होता है।

मैंने हमेशा सोचा कि यह अधिक सही होगा यदि पायथन ने केवल इंटरेक्टिव शेल के लिए ऐसा किया है, और आवश्यक स्क्रिप्ट को विभिन्न भागों से आयात करने के लिए स्क्रिप्ट की आवश्यकता है। इसके अलावा शायद अलग __ main__ हैंडलिंग गोले बनाम इंटरैक्टिव में अच्छा होगा। वैसे भी, सभी फ़ंक्शन देखें, और देखें कि यह उनके बिना क्या है:

dir (__builtins__)
...
del __builtins__
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.