[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
>>> 
Question

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




Analyze @staticmethod literally providing different insights.

A normal method of a class is an implicit dynamic method which takes the instance as first argument.
In contrast, a staticmethod does not take the instance as first argument, so is called 'static' .

A staticmethod is indeed such a normal function the same as those outside a class definition.
It is luckily grouped into the class just in order to stand closer where it is applied, or you might scroll around to find it.




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




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

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

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

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

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

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

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

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



मैंने सी ++ के साथ प्रोग्रामिंग भाषा सीखना शुरू किया और फिर जावा और फिर पायथन और इसलिए इस सवाल ने मुझे बहुत परेशान किया, जब तक कि मैं प्रत्येक के सरल उपयोग को समझ नहीं पाता।

कक्षा विधि: जावा और सी ++ के विपरीत पायथन में कन्स्ट्रक्टर ओवरलोडिंग नहीं है। और इसलिए इसे प्राप्त करने के लिए आप classmethod उपयोग कर सकते हैं। निम्नलिखित उदाहरण यह समझाएगा

आइए मान लें कि हमारे पास एक Person वर्ग है जो दो तर्क first_name और last_name लेता है और व्यक्ति का उदाहरण बनाता है।

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

अब, यदि आवश्यकता आती है जहां आपको केवल एक ही नाम का उपयोग करके कक्षा बनाने की आवश्यकता होती है, तो केवल first_name । आप अजगर में ऐसा कुछ नहीं कर सकते हैं

जब आप ऑब्जेक्ट (उदाहरण) बनाने का प्रयास करेंगे तो यह आपको एक त्रुटि देगा।

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def __init__(self, first_name):
        self.first_name = first_name

हालांकि, आप नीचे उल्लेखित @classmethod का उपयोग करके वही चीज़ प्राप्त कर सकते हैं

class Person(object):

    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @classmethod
    def get_person(cls, first_name):
        return cls(first_name, "")

स्टेटिक विधि:: यह अपेक्षाकृत सरल है, यह उदाहरण या कक्षा के लिए बाध्य नहीं है और आप क्लास नाम का उपयोग करके सरल कॉल कर सकते हैं।

तो मान लें कि उपरोक्त उदाहरण में आपको एक सत्यापन की आवश्यकता है कि first_name 20 वर्णों से अधिक नहीं होनी चाहिए, आप बस यह कर सकते हैं।

@staticmethod  
def validate_name(name):
    return len(name) <= 20

और आप कक्षा नाम का उपयोग कर बस कॉल कर सकते हैं

Person.validate_name("Gaurang Shah")



A quick hack-up ofotherwise identical methods in iPython reveals that @staticmethod yields marginal performance gains (in the nanoseconds), but otherwise it seems to serve no function. Also, any performance gains will probably be wiped out by the additional work of processing the method through staticmethod() during compilation (which happens prior to any code execution when you run a script).

कोड पठनीयता के लिए मैं @staticmethodतब तक टालना चाहूंगा जब तक कि आपकी विधि का उपयोग काम के भार के लिए नहीं किया जाएगा, जहां नैनोसेकंड गिनती है।




Python , एक वर्ग विधि को कक्षा को निहित पहला तर्क माना जाता है। ऑब्जेक्ट इंस्टेंस का वर्ग निश्चित रूप से पहले तर्क के रूप में पारित किया गया है। यह तब उपयोगी हो सकता है जब कोई कक्षा के कारखाने बनने की विधि चाहता है क्योंकि यह वास्तविक वर्ग (जिसे विधि कहा जाता है) को पहला तर्क माना जाता है, कोई भी सही वर्ग को तत्काल कर सकता है, भले ही उप-वर्गों का भी संबंध हो।

एक staticmethod सिर्फ एक वर्ग के अंदर परिभाषित एक समारोह है। यह वर्ग या उदाहरण के बारे में कुछ भी नहीं जानता जिसे इसे बुलाया गया था और केवल उन तर्कों को प्राप्त किया गया है जो किसी भी निहित पहले तर्क के बिना पारित किए गए थे। उदाहरण:

class Test(object):
    def foo(self, a):
        print "testing (%s,%s)"%(self,a)

    @classmethod
    def foo_classmethod(cls, a):
        print "testing foo_classmethod(%s,%s)"%(cls,a)

    @staticmethod
    def foo_staticmethod(a):
        print "testing foo_staticmethod(%s)"%a

test = Test()

staticmethods का उपयोग उन कार्यों को समूहबद्ध करने के लिए किया जाता है जिनमें कक्षा के वर्ग के साथ कुछ तार्किक संबंध होते हैं।




यह तय करने के लिए कि क्या @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



@classmethod का अर्थ है : जब इस विधि को बुलाया जाता है, तो हम वर्ग को उस वर्ग के उदाहरण के बजाय पहले तर्क के रूप में पास करते हैं (जैसा कि हम आमतौर पर विधियों के साथ करते हैं)। इसका मतलब है कि आप किसी विशेष उदाहरण के बजाय उस विधि के अंदर कक्षा और उसके गुणों का उपयोग कर सकते हैं।

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




@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 अपने कार्यान्वयन को बदलने का फैसला कर सकता है, शायद क्योंकि यह बहुत सामान्य है और एक से अधिक प्रकार के क्लस्टर को संभाल सकता है, इसलिए बस कक्षा का नाम जांचना पर्याप्त नहीं होगा।




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

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

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

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

>>> class Klaus:
        @classmethod
        def classmthd(*args):
            return args

        @staticmethod
        def staticmthd(*args):
            return args

# 1. Call classmethod without any arg
>>> Klaus.classmthd()  
(__main__.Klaus,)  # the class gets passed as the first argument

# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')

# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()  
()

# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)



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

@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() देखें।




Related