ऊपर आर्मिन Ronacher से
सटीक विवरण, अपने जवाब पर विस्तार इतना है कि मेरे जैसे शुरुआती यह अच्छी तरह से समझ:
तरीकों एक वर्ग में परिभाषित में अंतर, स्थिर या उदाहरण विधि (वहाँ अभी तक एक और प्रकार है कि क्या - वर्ग विधि - यहां पर चर्चा नहीं की गई है, इसलिए इस तथ्य को ध्यान में रखें कि वे किसी भी तरह से कक्षा के उदाहरण से बंधे हैं या नहीं। उदाहरण के लिए, कहते हैं कि क्या विधि क्रम
class C:
a = []
def foo(self):
pass
C# this is the class object
C.a # is a list object (class property object)
C.foo # is a function object (class property object)
c = C()
C# this is the class instance
वर्ग वस्तु के __dict__
शब्दकोश संपत्ति इस प्रकार
>>> C.__dict__['foo']
<function foo at 0x17d05b0>
सभी गुण और एक वर्ग वस्तु के तरीकों के संदर्भ में और धारण के दौरान वर्ग उदाहरण के लिए एक संदर्भ प्राप्त करता है
विधि foo ऊपर के रूप में पहुँचा जा सकता है। यहां ध्यान देने योग्य एक महत्वपूर्ण बात यह है कि पाइथन में सबकुछ एक वस्तु है और उपर्युक्त शब्दकोश में संदर्भ स्वयं अन्य वस्तुओं को इंगित कर रहे हैं। मुझे क्लास प्रॉपर्टी ऑब्जेक्ट्स - या ब्रेवटी के लिए मेरे उत्तर के दायरे में सीपीओ के रूप में कॉल करने दें।
यदि कोई सीपीओ एक वर्णक है, तो पाइथन व्याख्याकर्ता सीपीओ की __get__()
विधि को उस मूल्य तक पहुंचने के लिए कॉल करता है।
आदेश अगर एक सीपीओ निर्धारित करने के लिए एक विवरणक, अजगर interpretor की जांच करता है वर्णनकर्ता प्रोटोकॉल लागू करता है। डिस्क्रिप्टर प्रोटोकॉल को लागू करने के लिए 3 विधियों को लागू करना है
def __get__(self, instance, owner)
def __set__(self, instance, value)
def __delete__(self, instance)
उदा।
>>> C.__dict__['foo'].__get__(c, C)
जहां
self
सीपीओ है (यह सूची, str, समारोह आदि का एक उदाहरण हो सकता है) और रनटाइम
instance
द्वारा आपूर्ति की है वर्ग के उदाहरण है, जहां इस सीपीओ को परिभाषित किया गया है (उपरोक्त वस्तु 'सी') और हमें
owner
वह वर्ग है जहां यह सीपीओ परिभाषित किया गया है (उपरोक्त वर्ग वस्तु 'सी') और हमें आपूर्ति की आवश्यकता है। हालांकि ऐसा इसलिए है क्योंकि हम इसे सीपीओ पर बुला रहे हैं। जब हम उदाहरण पर इसे कहते हैं, हम न इस की आपूर्ति करने के बाद से क्रम उदाहरण या अपने वर्ग (बहुरूपता) की आपूर्ति कर सकते
value
सीपीओ के लिए लक्षित मूल्य है और हमारे द्वारा
आपूर्ति किए जाने की आवश्यकता की जरूरत है
सभी सीपीओ वर्णनकर्ता नहीं हैं। उदाहरण के लिए
>>> C.__dict__['foo'].__get__(None, C)
<function C.foo at 0x10a72f510>
>>> C.__dict__['a'].__get__(None, C)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__get__'
ऐसा इसलिए है क्योंकि सूची वर्ग वर्णनकर्ता प्रोटोकॉल को लागू नहीं करती है।
इस प्रकार c.foo(self)
में तर्क स्वयं की आवश्यकता है, क्योंकि इसके विधि हस्ताक्षर वास्तव में इस C.__dict__['foo'].__get__(c, C)
है (जैसा कि ऊपर बताया गया है, सी के रूप में यह पता चला जा सकता है या polymorphed की जरूरत नहीं है) और यह भी कारण है कि आप एक लेखन त्रुटि आप अगर मिलता है उस आवश्यक उदाहरण तर्क पास न करें।
आप पद्धति अभी भी वर्ग वस्तु सी के माध्यम से संदर्भित है और वर्ग उदाहरण के साथ बंधन दिखाई देती हैं तो इस समारोह में उदाहरण वस्तु के रूप में एक संदर्भ गुजर के माध्यम से हासिल की है।
यह बहुत बढ़िया है क्योंकि अगर आपने कोई संदर्भ नहीं रखा है या उदाहरण के लिए बाध्यकारी नहीं चुना है, तो सभी को आवश्यक था कि वर्णनकर्ता सीपीओ को लपेटने के लिए कक्षा लिखना और __get__()
विधि को किसी संदर्भ की आवश्यकता के लिए ओवरराइड करना था। इस नए वर्ग क्या हम एक डेकोरेटर फोन और कीवर्ड @staticmethod
class C(object):
@staticmethod
def foo():
pass
नया लिपटे सीपीओ foo
में संदर्भ के अभाव does not को एक त्रुटि फेंक और इस प्रकार सत्यापित किया जा सकता के माध्यम से लागू किया जाता है:
>>> C.__dict__['foo'].__get__(None, C)
<function foo at 0x17d0c30>
एक स्थिर विधि का मामला नामस्थान और कोड रखरखाव के अधिक से अधिक है (इसे कक्षा से बाहर ले जाना और इसे मॉड्यूल आदि में उपलब्ध करना)।
जब भी संभव हो, उदाहरण विधियों के बजाय स्थैतिक तरीकों को लिखना बेहतर हो सकता है, जब तक कि आपको तरीकों का आकलन करने की आवश्यकता न हो (जैसे पहुंच उदाहरण चर, कक्षा चर आदि)। वस्तुओं का अवांछित संदर्भ न रखकर कचरा संग्रह को कम करने का एक कारण है।
method_two() परिभाषा के अलावा कोई अंतर अमान्य नहीं है और इसकी कॉल विफल हो जाती है। –
@techtonik: method_two की परिभाषा के साथ कुछ भी गलत नहीं है! इसे गलत/अमान्य spec में कहा जा रहा है, यानी एक अतिरिक्त तर्क के साथ। – 0xc0de
आपका दोनों ** उदाहरण विधियां ** हैं, क्लास विधियों नहीं। परिभाषा में '@ classmethod' लागू करके आप एक [क्लास विधि] (https://docs.python.org/3/library/functions.html?highlight=classmethod#classmethod) बनाते हैं। पहले पैरामीटर को 'स्वयं' के बजाय 'cls' कहा जाना चाहिए और आपकी कक्षा के उदाहरण के बजाय कक्षा वस्तु प्राप्त होगी:' Test.method_three() 'और' a_test.method_three() 'समकक्ष हैं। –