python - शुरुआती के लिए @classmethod और @staticmethod का अर्थ?




oop static-methods (8)

क्या कोई मुझे पाइथन में @classmethod और @staticmethod का अर्थ समझा सकता है? मुझे अंतर और अर्थ जानने की जरूरत है।

जहां तक ​​मैं समझता हूं, @classmethod एक वर्ग को बताता है कि यह एक विधि है जिसे उप-वर्गों में विरासत में प्राप्त किया जाना चाहिए, या ... कुछ। हालांकि, इसका क्या मतलब है? @classmethod या @staticmethod या किसी भी @ परिभाषाओं को जोड़ने के बिना क्लास विधि को परिभाषित क्यों न करें?

टीएल; डॉ: मुझे उनका उपयोग कब करना चाहिए, मुझे उनका उपयोग क्यों करना चाहिए, और मुझे उनका उपयोग कैसे करना चाहिए?

मैं सी ++ के साथ बहुत उन्नत हूं, इसलिए अधिक उन्नत प्रोग्रामिंग अवधारणाओं का उपयोग करना कोई समस्या नहीं होनी चाहिए। यदि संभव हो तो मुझे एक संबंधित सी ++ उदाहरण दें।


@classmethod और @staticmethod का अर्थ?

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

मुझे उनका उपयोग कब करना चाहिए, मुझे उनका उपयोग क्यों करना चाहिए, और मुझे उनका उपयोग कैसे करना चाहिए?

आपको सजावटी की जरूरत नहीं है । लेकिन सिद्धांत पर कि आपको कार्यों के लिए तर्कों की संख्या को कम करना चाहिए (स्वच्छ कोडर देखें), वे केवल ऐसा करने के लिए उपयोगी हैं।

class Example(object):

    def regular_instance_method(self):
        """A function of an instance has access to every attribute of that 
        instance, including its class (and its attributes.)
        Not accepting at least one argument is a TypeError.
        Not understanding the semantics of that argument is a user error.
        """
        return some_function_f(self)

    @classmethod
    def a_class_method(cls):
        """A function of a class has access to every attribute of the class.
        Not accepting at least one argument is a TypeError.
        Not understanding the semantics of that argument is a user error.
        """
        return some_function_g(cls)

    @staticmethod
    def a_static_method():
        """A static method has no information about instances or classes
        unless explicitly given. It just lives in the class (and thus its 
        instances') namespace.
        """
        return some_function_h()

उदाहरण के तरीकों और वर्ग विधियों दोनों के लिए, कम से कम एक तर्क स्वीकार नहीं करना एक टाइपर है, लेकिन उस तर्क के अर्थशास्त्र को समझना एक उपयोगकर्ता त्रुटि नहीं है।

( some_function परिभाषित करें, उदाहरण के लिए:

some_function_h = some_function_g = some_function_f = lambda x=None: x

और यह काम करेगा।)

उदाहरण और कक्षाओं पर बिंदीदार लुकअप:

इस क्रम में एक उदाहरण पर एक बिंदीदार लुकअप किया जाता है - हम इसकी तलाश करते हैं:

  1. कक्षा नामस्थान में एक डेटा डिस्क्रिप्टर (एक संपत्ति की तरह)
  2. उदाहरण में डेटा __dict__
  3. कक्षा नामस्थान (विधियों) में एक गैर-डेटा वर्णनकर्ता।

नोट, एक उदाहरण पर एक बिंदीदार लुकअप इस तरह से लागू किया जाता है:

instance = Example()
instance.regular_instance_method 

और विधियां कॉल करने योग्य विशेषताएं हैं:

instance.regular_instance_method()

उदाहरण विधियों

तर्क, self , बिंदीदार लुकअप के माध्यम से निहित रूप से दिया जाता है।

आपको कक्षा के उदाहरणों से इंस्टेंस विधियों तक पहुंच प्राप्त करनी होगी।

>>> instance = Example()
>>> instance.regular_instance_method()
<__main__.Example object at 0x00000000399524E0>

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

तर्क, cls , निश्चित रूप से बिंदीदार लुकअप के माध्यम से दिया जाता है।

आप इस विधि को किसी उदाहरण या कक्षा (या उप-वर्ग) के माध्यम से एक्सेस कर सकते हैं।

>>> instance.a_class_method()
<class '__main__.Example'>
>>> Example.a_class_method()
<class '__main__.Example'>

स्थैतिक तरीकों

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

>>> print(instance.a_static_method())
None

फिर, मुझे उनका उपयोग कब करना चाहिए, मुझे उनका उपयोग क्यों करना चाहिए?

इनमें से प्रत्येक सूचना पद्धति बनाम विधि को पारित करने वाली जानकारी में प्रगतिशील रूप से अधिक प्रतिबंधित है।

जब आपको जानकारी की आवश्यकता नहीं होती है तो उनका उपयोग करें।

इससे आपके कार्यों और विधियों को कारण और बिना किसी कारण के कारण आसान हो जाता है।

किसके बारे में तर्क करना आसान है?

def function(x, y, z): ...

या

def function(y, z): ...

या

def function(z): ...

कम तर्क वाले कार्यों के बारे में तर्क करना आसान है। वे एकजुट होना भी आसान है।

ये उदाहरण, कक्षा, और स्थिर तरीकों के समान हैं। ध्यान में रखते हुए कि जब हमारे पास एक उदाहरण है, तो हमारे पास भी कक्षा है, फिर से, खुद से पूछें, जिसके बारे में तर्क करना आसान है ?:

def an_instance_method(self, arg, kwarg=None):
    cls = type(self)             # Also has the class of instance!
    ...

@classmethod
def a_class_method(cls, arg, kwarg=None):
    ...

@staticmethod
def a_static_method(arg, kwarg=None):
    ...

बिल्टिन उदाहरण

यहां मेरे कुछ पसंदीदा बिल्टिन उदाहरण दिए गए हैं:

str.maketrans स्थिर विधि string मॉड्यूल में एक फ़ंक्शन था, लेकिन str नामस्थान से इसे एक्सेस करने के लिए यह अधिक सुविधाजनक है।

>>> 'abc'.translate(str.maketrans({'a': 'b'}))
'bbc'

dict.fromkeys क्लास विधि कुंजी के एक dict.fromkeys से तत्काल एक नया शब्दकोश देता है:

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

जब subclassed, हम देखते हैं कि यह कक्षा की जानकारी एक वर्ग विधि के रूप में मिलता है, जो बहुत उपयोगी है:

>>> class MyDict(dict): pass
>>> type(MyDict.fromkeys('abc'))
<class '__main__.MyDict'> 

मेरी सलाह - निष्कर्ष

जब आपको कक्षा या उदाहरण तर्क की आवश्यकता नहीं होती है, तो स्थिर विधियों का उपयोग करें, लेकिन फ़ंक्शन ऑब्जेक्ट के उपयोग से संबंधित है, और यह फ़ंक्शन ऑब्जेक्ट के नामस्थान में सुविधाजनक है।

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


इसके बारे में सोचने का एक अलग तरीका यह है कि किसी के लिए उपयोगी हो सकता है ... एक क्लास विधि का इस्तेमाल सुपरक्लास में किया जाता है ताकि परिभाषित किया जा सके कि विभिन्न बाल वर्गों द्वारा इसे किस प्रकार व्यवहार किया जाना चाहिए। एक स्थिर विधि का उपयोग तब किया जाता है जब हम उस बच्चे की कक्षा के बावजूद एक ही चीज़ वापस लौटना चाहते हैं जिसे हम बुला रहे हैं।


कक्षा विधि कक्षा राज्य को संशोधित कर सकती है, यह कक्षा से बंधी है और इसमें सीएल पैरामीटर के रूप में शामिल हैं।

स्टेटिक विधि कक्षा राज्य को संशोधित नहीं कर सकती है, यह कक्षा से बंधी है और यह कक्षा या उदाहरण नहीं जानता है

class empDetails:
    def __init__(self,name,sal):
        self.name=name
        self.sal=sal
    @classmethod
    def increment(cls,name,none):
        return cls('yarramsetti',6000 + 500)
    @staticmethod
    def salChecking(sal):
        return sal > 6000

emp1=empDetails('durga prasad',6000)
emp2=empDetails.increment('yarramsetti',100)
# output is 'durga prasad'
print emp1.name
# output put is 6000
print emp1.sal
# output is 6500,because it change the sal variable
print emp2.sal
# output is 'yarramsetti' it change the state of name variable
print emp2.name
# output is True, because ,it change the state of sal variable
print empDetails.salChecking(6500)

मैं इस साइट पर एक नौसिखिया हूं, मैंने सभी उपरोक्त उत्तरों को पढ़ा है, और मुझे जो जानकारी चाहिए वह मिल गया है। हालांकि, मुझे ऊपर उठाने का अधिकार नहीं है। तो मैं जवाब के साथ पर अपनी शुरुआत करना चाहता हूं क्योंकि मैं इसे समझता हूं।

  • @staticmethod को विधि के पहले पैरामीटर के रूप में स्वयं या cls की आवश्यकता नहीं है
  • @staticmethod और @classmethod wrapped फ़ंक्शन को उदाहरण या क्लास वेरिएबल द्वारा बुलाया जा सकता है
  • @staticmethod सजाए गए फ़ंक्शन किसी प्रकार की 'अपरिवर्तनीय संपत्ति' को प्रभावित करते हैं जो उप-वर्ग विरासत अपने बेस क्लास फ़ंक्शन को ओवरराइट नहीं कर सकता है जो @staticmethod सजावट द्वारा लिपटा हुआ है।
  • @classmethod आवश्यकता है (कक्षा का नाम, यदि आप चाहते हैं तो आप वैरिएबल नाम बदल सकते हैं, लेकिन इसकी सलाह नहीं दी जाती है) फ़ंक्शन के पहले पैरामीटर के रूप में
  • @classmethod हमेशा subclass तरीके से उपयोग किया जाता है, subclass विरासत बेस क्लास फ़ंक्शन के प्रभाव को बदल सकता है, यानी @classmethod wrapped बेस क्लास फ़ंक्शन को विभिन्न उप-वर्गों द्वारा ओवरराइट किया जा सकता है।

रोस्टिस्लाव डिज़िंको का जवाब बहुत उपयुक्त है। मैंने सोचा कि जब आप अतिरिक्त कन्स्ट्रक्टर बना रहे हैं तो मैं @classmethod पर @staticmethod को चुनने के एक अन्य कारण को हाइलाइट कर सकता हूं।

उपर्युक्त उदाहरण में, रोस्टिस्लाव ने अन्यथा अस्वीकार्य पैरामीटर से Date ऑब्जेक्ट्स बनाने के लिए from_string from_string का उपयोग फैक्टरी के रूप में किया था। जैसा कि नीचे दिए गए कोड में दिखाया गया है, वही @staticmethod साथ किया जा सकता है:

class Date:
  def __init__(self, month, day, year):
    self.month = month
    self.day   = day
    self.year  = year


  def display(self):
    return "{0}-{1}-{2}".format(self.month, self.day, self.year)


  @staticmethod
  def millenium(month, day):
    return Date(month, day, 2000)

new_year = Date(1, 1, 2013)               # Creates a new Date object
millenium_new_year = Date.millenium(1, 1) # also creates a Date object. 

# Proof:
new_year.display()           # "1-1-2013"
millenium_new_year.display() # "1-1-2000"

isinstance(new_year, Date) # True
isinstance(millenium_new_year, Date) # True

इस प्रकार new_year और new_year दोनों Date वर्ग के उदाहरण हैं।

लेकिन, यदि आप बारीकी से देखते हैं, तो कारखाने की प्रक्रिया को Date ऑब्जेक्ट्स बनाने के लिए कड़ी मेहनत की जाती है, इससे कोई फर्क नहीं पड़ता। इसका अर्थ यह है कि यहां तक ​​कि यदि Date वर्ग उप-वर्गीकृत है, तो उप-वर्ग अभी भी सादा Date वस्तु (सबक्लास की किसी भी संपत्ति के बिना) बनाएंगे। नीचे दिए गए उदाहरण में देखें:

class DateTime(Date):
  def display(self):
      return "{0}-{1}-{2} - 00:00:00PM".format(self.month, self.day, self.year)


datetime1 = DateTime(10, 10, 1990)
datetime2 = DateTime.millenium(10, 10)

isinstance(datetime1, DateTime) # True
isinstance(datetime2, DateTime) # False

datetime1.display() # returns "10-10-1990 - 00:00:00PM"
datetime2.display() # returns "10-10-2000" because it's not a DateTime object but a Date object. Check the implementation of the millenium method on the Date class

DateTime उदाहरण नहीं है? WTF? वैसे यह @staticmethod सजावट का उपयोग किया जाता है।

ज्यादातर मामलों में, यह अवांछित है। यदि आप जो चाहते हैं वह फैक्ट्री विधि है जो उस वर्ग के बारे में जानती है जिसे इसे कहा जाता है, तो @classmethod आपको चाहिए।

Date.millenium को पुनर्लेखन के रूप में (यह उपर्युक्त कोड का एकमात्र हिस्सा है जो बदलता है)

@classmethod
def millenium(cls, month, day):
    return cls(month, day, 2000)

यह सुनिश्चित करता है कि class कठोर कोडित नहीं है बल्कि बल्कि सीखा है। cls कोई cls हो सकता है। परिणामी object सही रूप से cls का एक उदाहरण होगा। आइए इसका परीक्षण करें।

datetime1 = DateTime(10, 10, 1990)
datetime2 = DateTime.millenium(10, 10)

isinstance(datetime1, DateTime) # True
isinstance(datetime2, DateTime) # True


datetime1.display() # "10-10-1990 - 00:00:00PM"
datetime2.display() # "10-10-2000 - 00:00:00PM"

कारण यह है कि, जैसा कि आप अब तक जानते हैं, @classmethod बजाय @classmethod का उपयोग किया गया था


संक्षेप में, @classmehtod एक फैक्ट्री विधि के लिए एक सामान्य विधि बदल जाता है।

आइए इसे एक उदाहरण के साथ एक्सप्लोर करें:

class PythonBook:
    def __init__(self, name, author):
        self.name = name
        self.author = author
    def __repr__(self):
        return f'Book: {self.name}, Author: {self.author}'

एक @ वर्गीकरण के बिना, आपको एक-एक करके उदाहरण बनाने के लिए श्रम करना चाहिए और वे स्कार्ट किए गए हैं।

book1 = PythonBook('Learning Python', 'Mark Lutz')
In [20]: book1
Out[20]: Book: Learning Python, Author: Mark Lutz
book2 = PythonBook('Python Think', 'Allen B Dowey')
In [22]: book2
Out[22]: Book: Python Think, Author: Allen B Dowey

उदाहरण के लिए @classmethod के साथ

class PythonBook:
    def __init__(self, name, author):
        self.name = name
        self.author = author
    def __repr__(self):
        return f'Book: {self.name}, Author: {self.author}'
    @classmethod
    def book1(cls):
        return cls('Learning Python', 'Mark Lutz')
    @classmethod
    def book2(cls):
        return cls('Python Think', 'Allen B Dowey')

झसे आज़माओ:

In [31]: PythonBook.book1()
Out[31]: Book: Learning Python, Author: Mark Lutz
In [32]: PythonBook.book2()
Out[32]: Book: Python Think, Author: Allen B Dowey

देख? उदाहरणों को कक्षा परिभाषा के भीतर सफलतापूर्वक बनाया गया है और वे एक साथ एकत्र किए जाते हैं।

अंत में, @classmethod सजावट एक पारंपरिक विधि को फैक्ट्री विधि में परिवर्तित करता है, क्लासमेड का उपयोग करके आवश्यकतानुसार कई वैकल्पिक रचनाकारों को जोड़ना संभव हो जाता है।


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

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


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

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

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

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

here इस विषय के लिए अच्छा लिंक है।





class-method