सवाल पायथन में @staticmethod और @classmethod के बीच क्या अंतर है?


सजाए गए एक समारोह के बीच क्या अंतर है @staticmethod और एक के साथ सजाया @classmethod?


2675
2017-09-25 21:01


मूल


साफ-सफाई के लिए पाइथन में मॉड्यूल स्तर के कार्यों के रूप में स्थिर तरीके कभी-कभी बेहतर होती हैं। मॉड्यूल फ़ंक्शन के साथ केवल उस फ़ंक्शन को आयात करना आसान होता है जिसकी आपको आवश्यकता होती है और अनावश्यक "।" वाक्यविन्यास (मैं आपको उद्देश्य-सी देख रहा हूं)। वर्ग विधियों का अधिक उपयोग होता है क्योंकि इन्हें "फैक्ट्री पैटर्न" कार्यों को बनाने के लिए पॉलिमॉर्फिज्म के संयोजन में उपयोग किया जा सकता है। ऐसा इसलिए है क्योंकि कक्षा के तरीके कक्षा को एक अंतर्निहित पैरामीटर के रूप में प्राप्त करते हैं। - FistOfFury
टीएल; डॉ >> सामान्य तरीकों की तुलना में, स्थिर विधियों और वर्ग विधियों को कक्षा का उपयोग करके भी एक्सेस किया जा सकता है लेकिन वर्ग विधियों के विपरीत, स्थैतिक विधियां विरासत के माध्यम से अपरिवर्तनीय हैं। - imsrgadich


जवाब:


हो सकता है कि उदाहरण का थोड़ा सा कोड मदद करेगा: कॉल हस्ताक्षर में अंतर पर ध्यान दें foo, class_foo तथा static_foo:

class A(object):
    def foo(self,x):
        print "executing foo(%s,%s)"%(self,x)

    @classmethod
    def class_foo(cls,x):
        print "executing class_foo(%s,%s)"%(cls,x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)"%x    

a=A()

ऑब्जेक्ट इंस्टेंस एक विधि कहने का सामान्य तरीका नीचे है। वस्तु उदाहरण, a, निश्चित रूप से पहले तर्क के रूप में पारित किया गया है।

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

कक्षा के साथ, ऑब्जेक्ट इंस्टेंस का वर्ग निश्चित रूप से इसके बजाय पहले तर्क के रूप में पारित किया गया है self

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

आप भी कॉल कर सकते हैं class_foo कक्षा का उपयोग कर। वास्तव में, यदि आप कुछ होने के लिए परिभाषित करते हैं एक वर्ग विधि, शायद यह इसलिए है क्योंकि आप कक्षा के उदाहरण के बजाय कक्षा से इसे कॉल करना चाहते हैं। A.foo(1) एक टाइपरर उठाया होगा, लेकिन A.class_foo(1) ठीक काम करता है:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

क्लास विधियों के लिए लोगों द्वारा उपयोग किए जाने वाले लोगों का उपयोग करना है विरासत वैकल्पिक कन्स्ट्रक्टर


Staticmethods के साथ, न तो self (ऑब्जेक्ट इंस्टेंस) न ही cls (कक्षा) को पहले तर्क के रूप में निहित रूप से पारित किया गया है। वे सादे कार्यों की तरह व्यवहार करते हैं सिवाय इसके कि आप उन्हें एक उदाहरण या कक्षा से बुला सकते हैं:

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

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


foo बस एक समारोह है, लेकिन जब आप कॉल करते हैं a.foo आप सिर्फ समारोह नहीं मिलता है, आपको ऑब्जेक्ट इंस्टेंस के साथ फ़ंक्शन का "आंशिक रूप से लागू" संस्करण मिलता है a समारोह के लिए पहली तर्क के रूप में बाध्य। foo जबकि, 2 तर्क की उम्मीद है a.foo केवल 1 तर्क की उम्मीद है।

a निर्धारित तौर पे foo। नीचे "बाध्य" शब्द का अर्थ है:

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

साथ में a.class_foo, a के लिए बाध्य नहीं है class_fooबल्कि कक्षा A निर्धारित तौर पे class_foo

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

यहां, एक staticmethod के साथ, भले ही यह एक विधि है, a.static_foo बस वापस आती है बिना किसी तर्क के एक अच्छा 'ओले फ़ंक्शन। static_foo 1 तर्क की उम्मीद है, और a.static_foo 1 तर्क भी उम्मीद करता है।

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

और निश्चित रूप से वही बात होती है जब आप कॉल करते हैं static_foo कक्षा के साथ A बजाय।

print(A.static_foo)
# <function static_foo at 0xb7d479cc>

2320
2017-11-03 19:13



मुझे समझ में नहीं आता है कि staticmethod का उपयोग करने के लिए कैच है। हम बस एक साधारण बाहर के वर्ग समारोह का उपयोग कर सकते हैं। - Alcott
@ एल्कोट: हो सकता है कि आप किसी फ़ंक्शन को कक्षा में ले जाना चाहें क्योंकि यह तर्कसंगत रूप से कक्षा से संबंधित है। पायथन स्रोत कोड (उदा। मल्टीप्रोसेसिंग, कछुए, डिस्ट-पैकेज) में, इसका उपयोग मॉड्यूल नेमस्पेस से एकल-अंडरस्कोर "निजी" फ़ंक्शंस को "छुपाएं" करने के लिए किया जाता है। इसका उपयोग, हालांकि, कुछ मॉड्यूल में अत्यधिक केंद्रित है - शायद यह संकेत है कि यह मुख्य रूप से एक स्टाइलिस्ट चीज है। हालांकि मुझे इसका कोई उदाहरण नहीं मिला, @staticmethodsubclasses द्वारा overridable होने के द्वारा अपने कोड व्यवस्थित करने में मदद कर सकता है। इसके बिना आप मॉड्यूल नेमस्पेस में चारों ओर तैरने वाले फ़ंक्शन के वेरिएंट होंगे। - unutbu
... कुछ स्पष्टीकरण के साथ कहा पे तथा क्यूं कर उदाहरण, कक्षा या स्थैतिक तरीकों का उपयोग करने के लिए। आपने इसके बारे में एक भी शब्द नहीं दिया, लेकिन ओपी ने इसके बारे में भी पूछा नहीं। - MestreLion
@ एल्कोट: जैसा कि unutbu ने कहा, स्थिर तरीके एक संगठन / स्टाइलिस्ट विशेषता है। कभी-कभी एक मॉड्यूल में कई कक्षाएं होती हैं, और कुछ सहायक कार्यों को एए दिए गए वर्ग से तार्किक रूप से बंधे होते हैं, न कि दूसरों के लिए, इसलिए यह समझ में आता है कि मॉड्यूल को "मुक्त कार्यों" के साथ "प्रदूषित" नहीं करना है, और एक स्थिर का उपयोग करना बेहतर है मिश्रण वर्गों और फ़ंक्शन की खराब शैली पर भरोसा करने की विधि कोड में एक साथ डीफ़ को परिभाषित करने के लिए बस यह दिखाने के लिए कि वे "संबंधित" हैं - MestreLion
@unutbu: हालांकि आपको उस गिडो उद्धरण को हटा देना चाहिए: यह पायथन 2.2 रिलीज नोट्स के शुरुआती मसौदे से था, और इसे 2.2.3 में बदल दिया गया था: However, class methods are still useful in other places, for example, to program inheritable alternate constructors. यहां तक ​​कि मूल उद्धरण भी बहुत भ्रामक है, क्योंकि उसने केवल इतना कहा था कि अजगर विचलन का उपयोग नहीं होता है classmethod। लेकिन सिर्फ इसलिए कि पाइथन स्वयं किसी दिए गए फीचर का उपयोग नहीं करता है, इसका मतलब यह नहीं है कि यह एक बेकार विशेषता है। के बारे में सोचो जटिल आंकड़े या और भी sqrt: अजगर स्वयं का उपयोग नहीं कर सकता है, लेकिन यह पेशकश करने के लिए बेकार होने से बहुत दूर है - MestreLion


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

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

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

654
2017-09-25 21:05



एक staticmethod बेकार नहीं है - यह एक वर्ग में एक फ़ंक्शन डालने का एक तरीका है (क्योंकि यह तार्किक रूप से वहां से संबंधित है), जबकि यह इंगित करता है कि उसे कक्षा तक पहुंच की आवश्यकता नहीं है। - Tony Meyer
इसलिए केवल 'मूल रूप से' बेकार। इस तरह के संगठन, साथ ही निर्भरता इंजेक्शन, staticmethods के वैध उपयोग हैं, लेकिन चूंकि मॉड्यूल, जावा में कक्षाएं नहीं हैं, पाइथन में कोड संगठन के मूल तत्व हैं, उनका उपयोग और उपयोगिता दुर्लभ है। - Thomas Wouters
कक्षा के अंदर एक विधि को परिभाषित करने के बारे में तार्किक क्या है, जब उसके पास कक्षा या उसके उदाहरणों से कोई लेना देना नहीं है? - Ben James
शायद विरासत के लिए? स्टेटिक विधियों को विरासत में प्राप्त किया जा सकता है और उदाहरण के तरीकों और कक्षा विधियों की तरह ओवरराइड किया जा सकता है और लुकअप काम अपेक्षित (जावा में विपरीत) के रूप में काम करता है। स्टेटिक विधियों को वास्तव में क्लास या इंस्टेंस पर कॉल किए जाने पर स्थिर रूप से हल नहीं किया जाता है, इसलिए कक्षा और स्थिर तरीकों के बीच एकमात्र अंतर अंतर्निहित पहला तर्क है। - haridsv
वे एक क्लीनर नेमस्पेस भी बनाते हैं, और यह समझना आसान बनाता है कि फ़ंक्शन के साथ कक्षा के साथ कुछ करना है। - Imbrondir


मूल रूप से @classmethod एक विधि बनाता है जिसका पहला तर्क वह कक्षा है जिसे इसे क्लास इंस्टेंस के बजाए कहा जाता है, @staticmethodकोई अंतर्निहित तर्क नहीं है।


110
2017-09-25 21:07





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

@classmethod

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

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

@classmethod फॉर्म एक समारोह है    डेकोरेटर - का विवरण देखें   में कार्य परिभाषाएं समारोह   परिभाषाएँ ब्योरा हेतु।

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

कक्षा के तरीके सी ++ से अलग हैं   या जावा स्थैतिक तरीकों। अगर तुम चाहते हो   वे देखते हैं staticmethod() इसमें   अनुभाग।

@staticmethod

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

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

@staticmethod फॉर्म एक समारोह है    डेकोरेटर - का विवरण देखें   में कार्य परिभाषाएं समारोह   परिभाषाएँ ब्योरा हेतु।

इसे कक्षा में भी कहा जा सकता है   (जैसे कि C.f()) या एक उदाहरण पर   (जैसे कि C().f())। उदाहरण है   अपनी कक्षा को छोड़कर अनदेखा किया।

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


76
2017-11-03 19:23





यहाँ इस सवाल पर एक संक्षिप्त लेख है

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

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


55
2017-11-03 19:02



तो क्या इसका मतलब यह है कि एक staticmethod का उपयोग करके मैं हमेशा अभिभावक वर्ग से बंधे रहूंगा और कक्षा के साथ मैं कक्षा को बाध्य कर रहा हूं जिसमें मैंने कक्षा के तरीके को घोषित किया है (इस मामले में उप वर्ग)? - Mohan Gulati
नहीं। एक staticmethod का उपयोग करके आप बिल्कुल बाध्य नहीं हैं; कोई अंतर्निहित पहला पैरामीटर नहीं है। क्लासमेड का उपयोग करके, आप उस प्रथम श्रेणी के रूप में प्राप्त करते हैं जिस वर्ग को आपने विधि कहा है (यदि आपने इसे सीधे कक्षा में कहा है), या उस उदाहरण की कक्षा जिसे आपने विधि कहा है (यदि आपने इसे किसी उदाहरण पर कहा है)। - Matt Anderson
यह दिखाने के लिए थोड़ा सा विस्तार किया जा सकता है कि, कक्षा को पहले तर्क के रूप में रखते हुए, कक्षा विधियों के पास अन्य वर्ग विशेषताओं और विधियों तक सीधे पहुंच होती है, जबकि स्थैतिक विधियां नहीं होती हैं (उन्हें इसके लिए MyClass.attr को हार्डकोड करने की आवश्यकता होगी) - MestreLion


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

44
2018-04-22 15:40



दयालुता कि वास्तव में आपकी स्थिर विधि उदाहरण कर देता है एक वर्ग चर का उपयोग करें। आप शायद अपना उदाहरण सुधार सकते हैं। - Cilyan


पायथन में @staticmethod और @classmethod के बीच क्या अंतर है?

आपने पाइथन कोड को इस छद्म कोड की तरह देखा होगा, जो विभिन्न विधि प्रकारों के हस्ताक्षर दिखाता है और प्रत्येक को समझाने के लिए एक डॉकस्ट्रिंग प्रदान करता है:

class Foo(object):

    def a_normal_instance_method(self, arg_1, kwarg_2=None):
        '''
        Return a value that is a function of the instance with its
        attributes, and other arguments such as arg_1 and kwarg2
        '''

    @staticmethod
    def a_static_method(arg_0):
        '''
        Return a value that is a function of arg_0. It does not know the 
        instance or class it is called from.
        '''

    @classmethod
    def a_class_method(cls, arg1):
        '''
        Return a value that is a function of the class and other arguments.
        respects subclassing, it is called with the class it is called from.
        '''

सामान्य उदाहरण विधि

सबसे पहले मैं समझाऊंगा a_normal_instance_method। इसे ठीक से "उदाहरण विधि"जब एक आवृत्ति विधि का उपयोग किया जाता है, तो इसे आंशिक फ़ंक्शन के रूप में उपयोग किया जाता है (कुल फ़ंक्शन के विपरीत, स्रोत कोड में देखे जाने वाले सभी मानों के लिए परिभाषित), जब उपयोग किया जाता है, तो तर्कों में से पहला उदाहरण के रूप में पूर्वनिर्धारित होता है ऑब्जेक्ट का, इसके सभी दिए गए गुणों के साथ। इसमें ऑब्जेक्ट का उदाहरण है, और इसे ऑब्जेक्ट के उदाहरण से बुलाया जाना चाहिए। आमतौर पर, यह उदाहरण के विभिन्न गुणों तक पहुंच जाएगा।

उदाहरण के लिए, यह एक स्ट्रिंग का एक उदाहरण है:

', '

अगर हम उदाहरण विधि का उपयोग करते हैं, join इस स्ट्रिंग पर, एक और पुनरावर्तनीय में शामिल होने के लिए, यह स्पष्ट रूप से उदाहरण के एक समारोह है, पुनरावर्तनीय सूची के एक समारोह होने के अलावा, ['a', 'b', 'c']:

>>> ', '.join(['a', 'b', 'c'])
'a, b, c'

बाउंड विधियों

इंस्टेंस विधियों को बाद में उपयोग के लिए बिंदीदार लुकअप के माध्यम से बाध्य किया जा सकता है।

उदाहरण के लिए, यह बांधता है str.join करने के लिए विधि ':' उदाहरण:

>>> join_with_colons = ':'.join 

और बाद में हम इसे एक ऐसे फ़ंक्शन के रूप में उपयोग कर सकते हैं जिसका पहले से ही पहला तर्क है। इस तरह, यह उदाहरण पर आंशिक कार्य की तरह काम करता है:

>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'

स्टेटिक विधि

स्थिर विधि करता है नहीं उदाहरण को तर्क के रूप में लें।

यह एक मॉड्यूल स्तर समारोह के समान है।

हालांकि, एक मॉड्यूल स्तर समारोह मॉड्यूल में रहना चाहिए और विशेष रूप से अन्य स्थानों पर आयात किया जाना चाहिए जहां इसका उपयोग किया जाता है।

यदि यह वस्तु से जुड़ा हुआ है, हालांकि, यह वस्तु को आसानी से आयात और विरासत के माध्यम से भी पालन करेगा।

एक स्थिर विधि का एक उदाहरण है str.maketrans, से चले गए string पाइथन 3 में मॉड्यूल। यह एक अनुवाद तालिका खपत के लिए उपयुक्त बनाता है str.translate। स्ट्रिंग के उदाहरण से उपयोग किए जाने पर यह मूर्खतापूर्ण प्रतीत होता है, जैसा कि नीचे दिखाया गया है, लेकिन से फ़ंक्शन आयात करना string मॉड्यूल बल्कि बेकार है, और इसे कक्षा से कॉल करने में सक्षम होना अच्छा लगता है, जैसा कि अंदर है str.maketrans

# demonstrate same function whether called from instance or not:
>>> ', '.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}

पायथन 2 में, आपको इस फ़ंक्शन को तेजी से कम उपयोगी स्ट्रिंग मॉड्यूल से आयात करना होगा:

>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'

कक्षा विधि

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

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

>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}

जब हम dictclass dict, हम उसी कन्स्ट्रक्टर का उपयोग कर सकते हैं, जो सबक्लास का एक उदाहरण बनाता है।

>>> class MyDict(dict): 'A dict subclass, use to demo classmethods'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
<class '__main__.MyDict'>

देखें पांडा स्रोत कोड वैकल्पिक रचनाकारों के अन्य समान उदाहरणों के लिए, और आधिकारिक पायथन दस्तावेज भी देखें classmethod तथा staticmethod


38
2018-01-23 20:01