python @Staticmethod और @classmethod के बीच क्या अंतर है?





11 Answers

एक staticmethod एक तरीका है जो उस वर्ग या उदाहरण के बारे में कुछ नहीं जानता जिसे इसे बुलाया गया था। यह सिर्फ उन तर्कों को प्राप्त करता है जो पारित किए गए थे, कोई स्पष्ट पहला तर्क नहीं था। यह मूल रूप से पायथन में बेकार है - आप केवल staticmethod के बजाय मॉड्यूल फ़ंक्शन का उपयोग कर सकते हैं।

दूसरी तरफ, एक वर्ग विधि, एक ऐसी विधि है जो उस वर्ग को पारित करती है जिसे इसे बुलाया जाता है, या उदाहरण के वर्ग को जिसे पहले तर्क के रूप में कहा जाता था। यह तब उपयोगी होता है जब आप कक्षा के लिए एक कारखाना बनना चाहते हैं: चूंकि इसे वास्तविक वर्ग मिल जाता है, इसे पहले तर्क के रूप में बुलाया जाता था, फिर भी जब आप सबक्लास शामिल होते हैं, तब भी आप सही कक्षा को तुरंत चालू कर सकते हैं। उदाहरण के लिए देखें कि subclass पर कॉल करते समय dict.fromkeys() , एक classmethod, सबक्लास का उदाहरण देता है:

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 
python oop methods python-decorators

@staticmethod सजाए गए फ़ंक्शन और @staticmethod साथ सजाए गए फ़ंक्शन के बीच क्या अंतर है?




आधिकारिक पायथन दस्तावेज़:

@classmethod

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

class C:
    @classmethod
    def f(cls, arg1, arg2, ...): ... 

@classmethod फॉर्म एक फ़ंक्शन decorator - विवरण के लिए फ़ंक्शन परिभाषाओं में फ़ंक्शन परिभाषाओं का विवरण देखें।

इसे कक्षा में (जैसे Cf() ) या उदाहरण पर (जैसे C().f() ) कहा जा सकता है। उदाहरण को कक्षा के अलावा अनदेखा किया जाता है। यदि व्युत्पन्न वर्ग के लिए क्लास विधि कहा जाता है, तो व्युत्पन्न क्लास ऑब्जेक्ट को अंतर्निहित प्रथम तर्क के रूप में पारित किया जाता है।

क्लास विधियां सी ++ या जावा स्थैतिक तरीकों से अलग हैं। यदि आप उन्हें चाहते हैं, तो इस खंड में staticmethod() देखें।

@staticmethod

एक स्थैतिक विधि को एक निहित पहला तर्क प्राप्त नहीं होता है। एक स्थिर विधि घोषित करने के लिए, इस मुहावरे का उपयोग करें:

class C:
    @staticmethod
    def f(arg1, arg2, ...): ... 

@staticmethod फॉर्म एक फ़ंक्शन decorator - विवरण के लिए फ़ंक्शन परिभाषाओं में फ़ंक्शन परिभाषाओं का विवरण देखें।

इसे कक्षा में (जैसे Cf() ) या उदाहरण पर (जैसे C().f() ) कहा जा सकता है। उदाहरण को कक्षा के अलावा अनदेखा किया जाता है।

पायथन में स्टेटिक विधियां जावा या सी ++ में पाए गए समान हैं। एक और उन्नत अवधारणा के लिए, इस खंड में classmethod() देखें।




यह तय करने के लिए कि क्या @staticmethod या @classmethod का उपयोग करना है, आपको अपनी विधि के अंदर देखना होगा। यदि आपकी विधि आपकी कक्षा में अन्य चर / विधियों तक पहुंचती है तो @classmethod का उपयोग करें । दूसरी ओर, यदि आपकी विधि कक्षा के किसी अन्य भाग को छूती नहीं है तो @staticmethod का उपयोग करें।

class Apple:

    _counter = 0

    @staticmethod
    def about_apple():
        print('Apple is good for you.')

        # note you can still access other member of the class
        # but you have to use the class instance 
        # which is not very nice, because you have repeat yourself
        # 
        # For example:
        # @staticmethod
        #    print('Number of apples have been juiced: %s' % Apple._counter)
        #
        # @classmethod
        #    print('Number of apples have been juiced: %s' % cls._counter)
        #
        #    @classmethod is especially useful when you move your function to other class,
        #       you don't have to rename the class reference 

    @classmethod
    def make_apple_juice(cls, number_of_apples):
        print('Make juice:')
        for i in range(number_of_apples):
            cls._juice_this(i)

    @classmethod
    def _juice_this(cls, apple):
        print('Juicing %d...' % apple)
        cls._counter += 1



@decorators python 2.4 में जोड़े गए थे यदि आप अजगर <2.4 का उपयोग कर रहे हैं तो आप classmethod () और staticmethod () फ़ंक्शन का उपयोग कर सकते हैं।

उदाहरण के लिए, यदि आप एक फैक्ट्री विधि बनाना चाहते हैं (एक फ़ंक्शन क्लास के एक अलग कार्यान्वयन के उदाहरण को वापस करने के आधार पर देता है) तो आप ऐसा कुछ कर सकते हैं:

class Cluster(object):

    def _is_cluster_for(cls, name):
        """
        see if this class is the cluster with this name
        this is a classmethod
        """ 
        return cls.__name__ == name
    _is_cluster_for = classmethod(_is_cluster_for)

    #static method
    def getCluster(name):
        """
        static factory method, should be in Cluster class
        returns a cluster object for the given name
        """
        for cls in Cluster.__subclasses__():
            if cls._is_cluster_for(name):
                return cls()
    getCluster = staticmethod(getCluster)

यह भी देखें कि क्लासमेड और एक स्थैतिक विधि का उपयोग करने के लिए यह एक अच्छा उदाहरण है, स्थैतिक विधि क्लास से स्पष्ट रूप से संबंधित है, क्योंकि यह कक्षा क्लस्टर को आंतरिक रूप से उपयोग करता है। क्लासमेड को केवल कक्षा के बारे में जानकारी चाहिए, और ऑब्जेक्ट का कोई उदाहरण नहीं है।

_is_cluster_for विधि को _is_cluster_for विधि बनाने का एक और लाभ यह है कि _is_cluster_for अपने कार्यान्वयन को बदलने का फैसला कर सकता है, शायद क्योंकि यह बहुत सामान्य है और एक से अधिक प्रकार के क्लस्टर को संभाल सकता है, इसलिए बस कक्षा का नाम जांचना पर्याप्त नहीं होगा।




स्टेटिक तरीके:

  • कोई आत्म तर्क के साथ सरल कार्यों।
  • वर्ग विशेषताओं पर काम; उदाहरण विशेषताओं पर नहीं।
  • कक्षा और उदाहरण दोनों के माध्यम से बुलाया जा सकता है।
  • अंतर्निहित फ़ंक्शन staticmethod () का उपयोग उन्हें बनाने के लिए किया जाता है।

स्टेटिक तरीके के लाभ:

  • यह वर्गस्कोप में फ़ंक्शन नाम को स्थानीयकृत करता है
  • यह फ़ंक्शन कोड को उस स्थान के करीब ले जाता है जहां इसका उपयोग किया जाता है
  • मॉड्यूल-स्तरीय फ़ंक्शंस बनाम आयात करने के लिए अधिक सुविधाजनक है क्योंकि प्रत्येक विधि को विशेष रूप से आयात नहीं किया जाना चाहिए

    @staticmethod
    def some_static_method(*args, **kwds):
        pass
    

कक्षा के तरीके:

  • कार्य जिन्हें प्रथम श्रेणी के नाम के रूप में तर्क दिया गया है।
  • कक्षा और उदाहरण दोनों के माध्यम से बुलाया जा सकता है।
  • ये क्लासमेड इन-बिल्ट फ़ंक्शन के साथ बनाए गए हैं।

     @classmethod
     def some_class_method(cls, *args, **kwds):
         pass
    



पायथन में स्थैतिक, वर्ग या अमूर्त विधियों का उपयोग करने के बारे में निश्चित मार्गदर्शिका इस विषय के लिए एक अच्छा लिंक है, और इसे सारांश के रूप में सारांशित करें।

@staticmethod फ़ंक्शन किसी वर्ग के अंदर परिभाषित फ़ंक्शन से अधिक कुछ नहीं है। यह कक्षा को तुरंत चालू किए बिना कॉल करने योग्य है। यह परिभाषा विरासत के माध्यम से अपरिवर्तनीय है।

  • पाइथन को ऑब्जेक्ट के लिए बाध्य-विधि को तुरंत चालू करने की आवश्यकता नहीं है।
  • यह कोड की पठनीयता को आसान बनाता है, और यह वस्तु की स्थिति पर निर्भर नहीं है;

@classmethod फ़ंक्शन कक्षा को तत्काल किए बिना भी कॉल करने योग्य है, लेकिन इसकी परिभाषा उप वर्ग के अनुसार, मूल वर्ग नहीं, विरासत के माध्यम से उप-वर्ग द्वारा ओवरराइड की जा सकती है। ऐसा इसलिए है क्योंकि @classmethod फ़ंक्शन के लिए पहला तर्क हमेशा cls (वर्ग) होना चाहिए।

  • फ़ैक्टरी विधियों , जिनका उपयोग कक्षा के लिए उदाहरण बनाने के लिए किया जाता है उदाहरण के लिए प्री-प्रोसेसिंग का कुछ प्रकार।
  • स्थिर विधियों को कॉल करने वाली स्थिर विधियां : यदि आप कई स्थैतिक विधियों में एक स्थिर विधियों को विभाजित करते हैं, तो आपको कक्षा के नाम को हार्ड-कोड नहीं करना चाहिए बल्कि कक्षा विधियों का उपयोग करना चाहिए



Staticmethod बनाम classmethod के संबंध में एक और विचार विरासत के साथ आता है। मान लें कि आपके पास निम्न वर्ग है:

class Foo(object):
    @staticmethod
    def bar():
        return "In Foo"

और फिर आप एक बाल वर्ग में bar() को ओवरराइड करना चाहते हैं:

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"

यह काम करता है, लेकिन ध्यान दें कि अब बाल वर्ग ( Foo2 ) में bar() कार्यान्वयन अब उस वर्ग के लिए विशिष्ट कुछ भी नहीं ले सकता है। उदाहरण के लिए, कहें कि Foo2 में magic() नामक एक विधि थी जिसे आप bar() के Foo2 कार्यान्वयन में उपयोग करना चाहते हैं:

class Foo2(Foo):
    @staticmethod
    def bar():
        return "In Foo2"
    @staticmethod
    def magic():
        return "Something useful you'd like to use in bar, but now can't" 

यहां Foo2.magic() bar() Foo2.magic() में Foo2.magic() को कॉल करना होगा, लेकिन फिर आप स्वयं को दोहरा रहे हैं (यदि Foo2 का नाम बदलता है, तो आपको उस bar() विधि को अपडेट करना याद रखना होगा)।

मेरे लिए, यह खुला / बंद सिद्धांत का मामूली उल्लंघन है, क्योंकि Foo में किए गए निर्णय व्युत्पन्न वर्ग में सामान्य कोड को दोबारा करने की आपकी क्षमता को प्रभावित कर रहे हैं (यानी यह विस्तार के लिए कम खुला है)। यदि bar() एक classmethod थे classmethod हम ठीक होंगे:

class Foo(object):
    @classmethod
    def bar(cls):
        return "In Foo"

class Foo2(Foo):
    @classmethod
    def bar(cls):
        return "In Foo2 " + cls.magic()
    @classmethod
    def magic(cls):
        return "MAGIC"

print Foo2().bar()

देता है: In Foo2 MAGIC




मुझे @classmethod बनाम @staticmethod के साथ सजाए गए विधि के बीच समानता बताएं।

समानता: कक्षा के उदाहरण के बजाए, दोनों को कक्षा में ही बुलाया जा सकता है। तो, दोनों एक अर्थ में कक्षा के तरीके हैं

अंतर: एक वर्ग विधि कक्षा को स्वयं को पहली तर्क के रूप में प्राप्त करेगी, जबकि एक staticmethod नहीं है।

तो एक स्थिर विधि, एक अर्थ में, कक्षा के लिए बाध्य नहीं है और केवल वहां लटक रही है क्योंकि इसकी संबंधित कार्यक्षमता हो सकती है।

class C(object):
    @classmethod
    def fun(cls, arg1, arg2, ...):
       ....

fun: function that needs to be converted into a class method
returns: a class method for function.



@classmethod: उस वर्ग के बनाए गए सभी उदाहरणों के लिए एक साझा वैश्विक पहुंच बनाने के लिए उपयोग किया जा सकता है ..... जैसे एकाधिक उपयोगकर्ताओं द्वारा रिकॉर्ड अपडेट करना .... मैं कणिका को सिंगलेट बनाने के दौरान इसे पूर्ण रूप से उपयोग करता हूं ..: )

@ स्टेटिक विधि: कक्षा या उदाहरण से जुड़े होने के साथ कुछ लेना देना नहीं है ... लेकिन पठनीयता के लिए स्थैतिक विधि का उपयोग कर सकते हैं




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

class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m

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

class X(object):
    m=54 #will not be referenced

    @staticmethod
    def static_method():
        print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."



#!/usr/bin/python
#coding:utf-8

class Demo(object):
    def __init__(self,x):
        self.x = x

    @classmethod
    def addone(self, x):
        return x+1

    @staticmethod
    def addtwo(x):
        return x+2

    def addthree(self, x):
        return x+3

def main():
    print Demo.addone(2)
    print Demo.addtwo(2)

    #print Demo.addthree(2) #Error
    demo = Demo(2)
    print demo.addthree(2)


if __name__ == '__main__':
    main()





Related