मुझे @classmethod का उपयोग कब करना चाहिए और कब डीफ़ मैथड (स्वयं)?


88

मैंने पहले इस्तेमाल नहीं किए गए एक Django ऐप को एकीकृत करते हुए, मैंने कक्षाओं में कार्यों को परिभाषित करने के लिए उपयोग किए जाने वाले दो अलग-अलग तरीकों को पाया। लेखक उन दोनों को बहुत ही जानबूझकर उपयोग करने लगता है। पहले एक मैं खुद एक बहुत का उपयोग करें:

class Dummy(object):

    def some_function(self,*args,**kwargs):
        do something here
        self is the class instance

दूसरा वह है जिसका मैं उपयोग नहीं करता हूं, ज्यादातर इसलिए क्योंकि मुझे समझ नहीं आता कि इसका उपयोग कब करना है, और इसके लिए क्या है:

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        do something here
        cls refers to what?

पायथन डॉक्स में classmethodडेकोरेटर को इस वाक्य के साथ समझाया गया है:

एक वर्ग विधि कक्षा को पहले तर्क के रूप में प्राप्त करती है, ठीक उसी तरह जैसे कि एक इंस्टेंस विधि उदाहरण प्राप्त करती है।

तो मुझे लगता है कि खुद clsको संदर्भित करता Dummyहै ( class, उदाहरण नहीं)। मुझे समझ में नहीं आया कि यह क्यों मौजूद है, क्योंकि मैं हमेशा ऐसा कर सकता था:

type(self).do_something_with_the_class

क्या यह सिर्फ स्पष्टता के लिए है, या क्या मुझे सबसे महत्वपूर्ण हिस्सा याद है: डरावना और आकर्षक चीजें जो इसके बिना नहीं हो सकती थीं?

जवाबों:


70

आपका अनुमान सही है - आप समझते हैं कि classmethod काम कैसे होता है

ऐसा क्यों है कि इन विधियों को उदाहरण पर या कक्षा पर दोनों कहा जा सकता है (दोनों ही मामलों में, कक्षा ऑब्जेक्ट को पहले तर्क के रूप में पारित किया जाएगा):

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        print cls

#both of these will have exactly the same effect
Dummy.some_function()
Dummy().some_function()

उदाहरणों पर इनका उपयोग करने पर : उदाहरण के लिए क्लासमेथोड को कॉल करने के लिए कम से कम दो मुख्य उपयोग हैं:

  1. self.some_function()उस वर्ग के बजाय some_functionवास्तविक प्रकार के संस्करण को कॉल करेगा self, जिसमें वह कॉल दिखाई देती है (और यदि वर्ग का नाम बदल दिया जाता है) पर ध्यान देने की आवश्यकता नहीं होगी; तथा
  2. ऐसे मामलों में जहां some_functionकुछ प्रोटोकॉल को लागू करना आवश्यक है, लेकिन अकेले क्लास ऑब्जेक्ट पर कॉल करने के लिए उपयोगी है।

इसके साथ अंतरstaticmethod : परिभाषित करने के तरीकों का एक और तरीका है जो इंस्टेंस डेटा तक नहीं पहुंचता है, जिसे कहा जाता है staticmethod। यह एक ऐसी विधि बनाता है जिसे एक अंतर्निहित पहला तर्क बिल्कुल नहीं मिलता है; तदनुसार यह उस उदाहरण या वर्ग के बारे में कोई जानकारी नहीं दी जाएगी जिस पर उसे बुलाया गया था।

In [6]: class Foo(object): some_static = staticmethod(lambda x: x+1)

In [7]: Foo.some_static(1)
Out[7]: 2

In [8]: Foo().some_static(1)
Out[8]: 2

In [9]: class Bar(Foo): some_static = staticmethod(lambda x: x*2)

In [10]: Bar.some_static(1)
Out[10]: 2

In [11]: Bar().some_static(1)
Out[11]: 2

इसके लिए मैंने जो मुख्य उपयोग पाया है वह एक मौजूदा फ़ंक्शन (जो प्राप्त करने की उम्मीद नहीं करता है self) को एक वर्ग (या ऑब्जेक्ट) पर एक विधि के रूप में अनुकूलित करना है ।


2
अच्छा एक: मुझे जवाब पसंद है कि कैसे - क्यों में विभाजित किया जा रहा है। जहाँ तक मुझे मिला अब @classmethod एक उदाहरण की आवश्यकता के बिना फ़ंक्शन का उपयोग करने की अनुमति देता है। यह वही है जो मैं देख रहा था, धन्यवाद।
marue

1
@marcin ट्रू डक टाइपिंग इसे कुछ अन्य आयाम देती है। यह चीजों को नहीं लिखने के बारे में अधिक था जैसे self.foo()कि यह कब होना चाहिए Bar.foo()
Voo

5
@Voo वास्तव में, self.foo()बेहतर है, क्योंकि selfएक उपवर्ग का एक उदाहरण हो सकता है जो अपने आप को लागू करता है foo
मार्सिन

1
@ मारकिन मुझे लगता है कि यह इस बात पर निर्भर करता है कि आप क्या हासिल करना चाहते हैं। लेकिन मुझे आपकी बात समझ आ गयी है।
marue

1
आपको Bar, जैसा कि है 1+1 == 2 == 1*2, के लिए एक अलग लैम्ब्डा का उपयोग करना चाहिए , इसलिए दिखाए गए परिणामों से यह बताना असंभव है कि Bar().static_methodवास्तव में कहा जाता है।
जॉर्ज वी। रेली

0

मूल रूप से, आपको एक @classmethod का उपयोग करना चाहिए जब आपको पता चले कि विधि की परिभाषा को परिवर्तित नहीं किया जाएगा या ओवरराइड नहीं किया जाएगा।

एक अतिरिक्त: मूल रूप से, क्लास के तरीके तेज़ हैं, फिर ऑब्जेक्ट विधियाँ, क्योंकि त्वरित करने की आवश्यकता नहीं है और कम मेमोरी की आवश्यकता है।


-3

यदि आप डेकोरेटर @classmethod जोड़ते हैं, तो इसका मतलब है कि आप उस विधि को जावा या C ++ की स्थिर विधि के रूप में बनाने जा रहे हैं। (स्थैतिक विधि एक सामान्य शब्द है जो मुझे लगता है ;) ) पायथन में @staticmethod भी है। और classmethod और staticmethod के बीच अंतर यह है कि क्या आप तर्क या classname का उपयोग करके वर्ग या स्थिर चर तक पहुँच सकते हैं।

class TestMethod(object):
    cls_var = 1
    @classmethod
    def class_method(cls):
        cls.cls_var += 1
        print cls.cls_var

    @staticmethod
    def static_method():
        TestMethod.cls_var += 1
        print TestMethod.cls_var
#call each method from class itself.
TestMethod.class_method()
TestMethod.static_method()

#construct instances
testMethodInst1 = TestMethod()    
testMethodInst2 = TestMethod()   

#call each method from instances
testMethodInst1.class_method()
testMethodInst2.static_method()

वे सभी कक्षाएं 1 से cls.cls_var को बढ़ाती हैं और इसे प्रिंट करती हैं।

और इन वर्गों के साथ निर्मित समान दायरे या उदाहरणों पर समान नाम का उपयोग करने वाली प्रत्येक कक्षाएं उन तरीकों को साझा करने जा रही हैं। केवल एक TestMethod.cls_var है और केवल एक TestMethod.class_method (), TestMethod.static_method () है

और महत्वपूर्ण प्रश्न। क्यों इन विधि की आवश्यकता होगी।

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


2
(ए) स्टेटिक तरीके कुछ और हैं; (बी) क्लासमेथोड हर वर्ग द्वारा साझा नहीं किए जाते हैं।
मार्सिन

@ मेरी धन्यवाद मुझे अपनी स्पष्ट परिभाषा और वह सब बताने के लिए धन्यवाद।
रयान किम ने
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.