कक्षा के तरीकों का उद्देश्य क्या है?


250

मैं अपने आप को पायथन सिखा रहा हूं और मेरा सबसे हाल का सबक यह था कि पायथन जावा नहीं है , और इसलिए मैंने अपने सभी क्लास के तरीकों को फ़ंक्शन में बदल दिया।

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

क्या किसी के पास पायथन में क्लास पद्धति का उपयोग करने का एक अच्छा उदाहरण है या कम से कम कोई मुझे बता सकता है कि क्लास के तरीकों का उपयोग कैसे किया जा सकता है?

जवाबों:


178

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

यदि आपके पास एक वर्ग है MyClass, और एक मॉड्यूल-स्तरीय फ़ंक्शन है जो MyClass (कारखाने, निर्भरता इंजेक्शन ठूंठ, आदि) पर संचालित होता है, तो एक बनाएं classmethod। तब यह उपवर्गों के लिए उपलब्ध होगा।


समझा। लेकिन, कैसे के बारे में अगर मैं सिर्फ एक विधि को वर्गीकृत करना चाहता हूं, जिसे MyClass की आवश्यकता नहीं है, लेकिन फिर भी किसी तरह से अगर मैं अन्य MyClass में समूह बनाता हूं, तो इसका कोई मतलब नहीं है? मैं इसे हेल्पर मॉड्यूल में स्थानांतरित करने के बारे में सोच सकता हूं, हालांकि
स्वेड

मेरे पास मूल से संबंधित एक प्रश्न है, शायद आप उसी समय में इसका उत्तर दे सकते हैं? किसी वस्तु के वर्ग विधियों को कॉल करने का तरीका "बेहतर" है, या "अधिक मुहावरेदार": obj.cls_mthd(...)या type(obj).cls_mthd(...)?
एलेक्सी

63

कारखाने के तरीके (वैकल्पिक निर्माणकर्ता) वास्तव में वर्ग विधियों का एक उत्कृष्ट उदाहरण हैं।

मूल रूप से, वर्ग विधियाँ उपयुक्त होती हैं, कभी भी आप एक ऐसी विधि करना चाहेंगे जो स्वाभाविक रूप से कक्षा के नाम स्थान में फिट हो, लेकिन वर्ग के किसी विशेष उदाहरण से संबद्ध नहीं है।

एक उदाहरण के रूप में, उत्कृष्ट यूनिपाठ मॉड्यूल में:

वर्तमान निर्देशिका

  • Path.cwd()
    • वास्तविक वर्तमान निर्देशिका लौटाएं; जैसे, Path("/tmp/my_temp_dir")। यह एक वर्ग विधि है।
  • .chdir()
    • स्वयं को वर्तमान निर्देशिका बनाएं।

जैसा कि वर्तमान निर्देशिका विस्तृत है, cwdविधि में कोई विशेष उदाहरण नहीं है जिसके साथ इसे संबद्ध होना चाहिए। हालाँकि, cwdकिसी दिए गए Pathइंस्टेंस की डायरेक्टरी को बदलना वास्तव में एक इंस्टेंस विधि होना चाहिए।

हम्म् ... जैसा Path.cwd()कि वास्तव में एक Pathउदाहरण है, मुझे लगता है कि यह एक कारखाना तरीका माना जा सकता है ...


1
हाँ ... कारखाने के तरीके पहली चीज़ थे जो दिमाग में आए। इसके अलावा उन पंक्तियों के साथ चीजें हैं जो एक सिंगलटन पैटर्न को लागू करेंगे, जैसे: getAndOptallyCreateSomeSingleInstanceOfSomeResource ()
Jemenake

3
अजगर में, वे स्थिर विधियां हैं, वर्ग विधियां नहीं।
Jaykul

46

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

जब आप सेट-अप कर रहे हैं या गणना कर रहे हैं तो क्लास मेथड्स आवश्यक हैं, जो कि वास्तविक उदाहरण के निर्माण से पहले होता है, क्योंकि जब तक उदाहरण मौजूद है, तब तक आप स्पष्ट रूप से इंस्टेंस को अपनी विधि कॉल के लिए उदाहरण के रूप में उपयोग नहीं कर सकते। SQLAlchemy स्रोत कोड में एक अच्छा उदाहरण देखा जा सकता है; dbapi()निम्नलिखित लिंक पर कक्षा विधि पर एक नज़र डालें :

https://github.com/zzzeek/sqlalchemy/blob/ab6946769742602e40fb9ed9dde5f642885d1906/lib/sqlalchemy/dialects/mssql/pymssql.py#L47

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


टूटी हुई कड़ी, कृपया समायोजित करें
पियोटनी

28

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

इसलिए मैंने @classmethodइसे प्राप्त करने के लिए वर्ग चर और सज्जाकार का उपयोग किया।

अपनी सरल लॉगिंग कक्षा के साथ, मैं निम्नलिखित कार्य कर सकता हूं:

Logger._level = Logger.DEBUG

फिर, मेरे कोड में, अगर मैं डिबगिंग जानकारी का एक गुच्छा बाहर थूकना चाहता था, मुझे बस कोड करना था

Logger.debug( "this is some annoying message I only want to see while debugging" )

त्रुटियों के साथ बाहर रखा जा सकता है

Logger.error( "Wow, something really awful happened." )

"उत्पादन" वातावरण में, मैं निर्दिष्ट कर सकता हूं

Logger._level = Logger.ERROR

और अब, केवल त्रुटि संदेश आउटपुट होगा। डिबग संदेश मुद्रित नहीं किया जाएगा।

यहाँ मेरी कक्षा है:

class Logger :
    ''' Handles logging of debugging and error messages. '''

    DEBUG = 5
    INFO  = 4
    WARN  = 3
    ERROR = 2
    FATAL = 1
    _level = DEBUG

    def __init__( self ) :
        Logger._level = Logger.DEBUG

    @classmethod
    def isLevel( cls, level ) :
        return cls._level >= level

    @classmethod
    def debug( cls, message ) :
        if cls.isLevel( Logger.DEBUG ) :
            print "DEBUG:  " + message

    @classmethod
    def info( cls, message ) :
        if cls.isLevel( Logger.INFO ) :
            print "INFO :  " + message

    @classmethod
    def warn( cls, message ) :
        if cls.isLevel( Logger.WARN ) :
            print "WARN :  " + message

    @classmethod
    def error( cls, message ) :
        if cls.isLevel( Logger.ERROR ) :
            print "ERROR:  " + message

    @classmethod
    def fatal( cls, message ) :
        if cls.isLevel( Logger.FATAL ) :
            print "FATAL:  " + message

और कुछ कोड जो इसे थोड़ा परीक्षण करते हैं:

def logAll() :
    Logger.debug( "This is a Debug message." )
    Logger.info ( "This is a Info  message." )
    Logger.warn ( "This is a Warn  message." )
    Logger.error( "This is a Error message." )
    Logger.fatal( "This is a Fatal message." )

if __name__ == '__main__' :

    print "Should see all DEBUG and higher"
    Logger._level = Logger.DEBUG
    logAll()

    print "Should see all ERROR and higher"
    Logger._level = Logger.ERROR
    logAll()

10
यह मुझे ऐसा नहीं लगता है कि अच्छे उदाहरण वर्ग विधि के लिए अच्छे हैं क्योंकि यह सभी जटिल तरीकों से कम-से-कम सभी तरीके से किया जा सकता है, मॉड्यूल स्तर के कार्यों को करना और पूरी तरह से कक्षा के साथ दूर करना।
मार्टिउन

10
ओह, इससे भी महत्वपूर्ण बात, पायथन लॉगिंग क्लास का उपयोग करने के लिए एक बहुत ही सरल प्रदान करता है। इष्टतम समाधान की तुलना में कम बनाने से भी बदतर, मैंने पहिया को सुदृढ़ किया। डबल हाथ थप्पड़। लेकिन यह एक काम करने का उदाहरण प्रदान करता है, कम से कम। यकीन नहीं है कि मैं वर्ग से छुटकारा पाने से सहमत हूं, हालांकि, एक वैचारिक स्तर पर। कभी-कभी आप आसान री-यूज़ के लिए कोड को इनकैप्सुलेट करना चाहते हैं, और री-यूज़ के लिए एक लॉगिंग मेथड एक बेहतरीन लक्ष्य है।
मैरवो

3
तुम एक staticmethod का उपयोग क्यों नहीं करेंगे?
bdforbes


11

जब कोई उपयोगकर्ता मेरी वेबसाइट पर लॉग इन करता है, तो उपयोगकर्ता () ऑब्जेक्ट को उपयोगकर्ता नाम और पासवर्ड से तुरंत हटा दिया जाता है।

अगर मुझे लॉग इन करने के लिए उपयोगकर्ता के बिना एक उपयोगकर्ता ऑब्जेक्ट की आवश्यकता होती है (उदाहरण के लिए एक व्यवस्थापक उपयोगकर्ता किसी अन्य उपयोगकर्ता खाते को हटाना चाह सकता है, तो मुझे उस उपयोगकर्ता को तुरंत हटाने और उसकी डिलीट विधि को कॉल करने की आवश्यकता है):

उपयोगकर्ता ऑब्जेक्ट को हथियाने के लिए मेरे पास वर्ग विधियाँ हैं।

class User():
    #lots of code
    #...
    # more code

    @classmethod
    def get_by_username(cls, username):
        return cls.query(cls.username == username).get()

    @classmethod
    def get_by_auth_id(cls, auth_id):
        return cls.query(cls.auth_id == auth_id).get()

9

मुझे लगता है कि सबसे स्पष्ट जवाब अमनकॉव का है। यह उबलता है कि आप अपने कोड को कैसे व्यवस्थित करना चाहते हैं। आप मॉड्यूल स्तर के कार्यों के रूप में सब कुछ लिख सकते हैं जो मॉड्यूल के नाम स्थान में लिपटे हुए हैं

module.py (file 1)
---------
def f1() : pass
def f2() : pass
def f3() : pass


usage.py (file 2)
--------
from module import *
f1()
f2()
f3()
def f4():pass 
def f5():pass

usage1.py (file 3)
-------------------
from usage import f4,f5
f4()
f5()

उपरोक्त प्रक्रियात्मक कोड अच्छी तरह से व्यवस्थित नहीं है, जैसा कि आप देख सकते हैं कि केवल 3 मॉड्यूल के बाद यह भ्रमित हो जाता है, प्रत्येक विधि क्या है? आप फ़ंक्शंस के लिए लंबे वर्णनात्मक नामों का उपयोग कर सकते हैं (जैसे जावा में) लेकिन फिर भी आपका कोड बहुत जल्दी असहनीय हो जाता है।

ऑब्जेक्ट ओरिएंटेड तरीका यह है कि अपने कोड को मैनेज करने योग्य ब्लॉक यानी कक्षाओं और ऑब्जेक्ट्स में तोड़ दिया जाए और फ़ंक्शंस ऑब्जेक्ट्स इंस्टेंस के साथ या कक्षाओं के साथ जुड़े जा सकते हैं।

वर्ग फ़ंक्शंस के साथ आप मॉड्यूल कोड फ़ंक्शंस की तुलना में अपने कोड में विभाजन का एक और स्तर प्राप्त करते हैं। इसलिए आप उन्हें एक कार्य के लिए एक वर्ग के भीतर संबंधित कार्यों को समूह बना सकते हैं जो आपको उस वर्ग को सौंपा गया है। उदाहरण के लिए आप एक फ़ाइल उपयोगिता वर्ग बना सकते हैं:

class FileUtil ():
  def copy(source,dest):pass
  def move(source,dest):pass
  def copyDir(source,dest):pass
  def moveDir(source,dest):pass

//usage
FileUtil.copy("1.txt","2.txt")
FileUtil.moveDir("dir1","dir2")

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


1
F1 (), f2 () इत्यादि का उपयोग करने के लिए, जैसे आपने किया, क्या आपको मॉड्यूल आयात * और आयात आयात * से उपयोग नहीं करना चाहिए?
जाब्लास्को

@ जाब्लास्को I ने भ्रम को दूर करने के लिए आयात कथनों को ठीक किया, हाँ यदि आप उस मॉड्यूल को आयात करते हैं जिसे आपको मॉड्यूल नाम के साथ फ़ंक्शन को उपसर्ग करना है। आयात मॉड्यूल -> मॉड्यूल .f1 () आदि
फायरफिल

मैं इस जवाब से असहमत हूं; अजगर जावा नहीं है। उदाहरण में खराब नामों की जानबूझकर पसंद के कारण केवल असहनीय कोड का मुद्दा स्पष्ट रूप से उठता है। यदि इसके बजाय आपने FileUtilक्लास के तरीकों को एक file_utilमॉड्यूल के कार्यों के रूप में दोहराया है , तो यह तुलनीय होगा और ओओपी का दुरुपयोग नहीं करेगा जब कोई वस्तु वास्तव में मौजूद नहीं होती है (वास्तव में आप यह तर्क दे सकते हैं कि यह बेहतर है, क्योंकि आप किसी from file_util import FileUtilअन्य क्रिया के साथ समाप्त नहीं होते हैं )। import file_utilइसके बजाय प्रक्रियात्मक कोड में नाम संघर्ष को टाला जा सकता है from file_util import ...
ForgottenUmbrella

7

ईमानदारी से? मैंने कभी भी staticmethod या classmethod का उपयोग नहीं पाया है। मैंने अभी तक एक ऑपरेशन देखा है जिसे वैश्विक फ़ंक्शन या इंस्टेंस विधि का उपयोग करके नहीं किया जा सकता है।

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

आमतौर पर, मैं देखता हूं कि लोग स्टेथमैथोड्स और क्लासमेथोड्स का उपयोग कर रहे हैं, जब उन्हें वास्तव में करने की जरूरत है तो अजगर के मॉड्यूल-स्तरीय नेमस्पेस का बेहतर उपयोग करें।


1
निजी: _variable_name और संरक्षित: __variable_name
ब्रैडली क्रेडर

1
एक अपरिहार्य उपयोग unittest's setUpClass और tearDownClass है। आप unittests का उपयोग कर रहे हैं, है ना? :)
dbn

7

यह आपको जेनेरिक क्लास के तरीकों को लिखने की अनुमति देता है जिसका उपयोग आप किसी भी संगत क्लास के साथ कर सकते हैं।

उदाहरण के लिए:

@classmethod
def get_name(cls):
    print cls.name

class C:
    name = "tester"

C.get_name = get_name

#call it:
C.get_name()

यदि आप इसका उपयोग नहीं करते हैं, @classmethodतो आप इसे स्व-कीवर्ड के साथ कर सकते हैं, लेकिन इसके लिए कक्षा का एक उदाहरण चाहिए:

def get_name(self):
    print self.name

class C:
    name = "tester"

C.get_name = get_name

#call it:
C().get_name() #<-note the its an instance of class C

5

मैं PHP के साथ काम करता था और हाल ही में मैं खुद से पूछ रहा था, इस क्लासमैथोड के साथ क्या चल रहा है? पायथन मैनुअल बहुत तकनीकी है और शब्दों में बहुत छोटा है इसलिए यह उस सुविधा को समझने में मदद नहीं करेगा। मैं गुगली कर रहा था और गुगली कर रहा था और मुझे जवाब मिला -> http://code.anjanesh.net/2007/12/python-classmethods.html

यदि आप इसे क्लिक करने के लिए आलसी हैं। मेरा स्पष्टीकरण छोटा और नीचे है। :)

PHP में (शायद आप सभी लोग PHP नहीं जानते हैं, लेकिन यह भाषा इतनी सीधी है कि हर किसी को समझना चाहिए कि मैं किस बारे में बात कर रहा हूं) हमारे पास इस तरह स्थिर चर हैं:


class A
{

    static protected $inner_var = null;

    static public function echoInnerVar()
    {
        echo self::$inner_var."\n";
    }

    static public function setInnerVar($v)
    {
        self::$inner_var = $v;
    }

}

class B extends A
{
}

A::setInnerVar(10);
B::setInnerVar(20);

A::echoInnerVar();
B::echoInnerVar();

आउटपुट दोनों मामलों में होगा 20।

हालांकि अजगर में हम @classmethod डेकोरेटर जोड़ सकते हैं और इस प्रकार क्रमशः 10 और 20 का उत्पादन संभव है। उदाहरण:


class A(object):
    inner_var = 0

    @classmethod
    def setInnerVar(cls, value):
        cls.inner_var = value

    @classmethod
    def echoInnerVar(cls):
        print cls.inner_var


class B(A):
    pass


A.setInnerVar(10)
B.setInnerVar(20)

A.echoInnerVar()
B.echoInnerVar()

स्मार्ट, नहीं है?


अपने अजगर उदाहरण के साथ एक संभावित समस्या है, तो है B.setInnerVar(20)बाहर छोड़ दिया गया था, इसे प्रिंट होता 10है कि कोई दो बार (बजाय दूसरे echoInnerBar () कॉल पर एक त्रुटि दे inner_varपरिभाषित किया गया था।
मार्टिन्यू

5

क्लास के तरीके एक "सिमेंटिक शुगर" प्रदान करते हैं (यह नहीं जानते कि क्या यह शब्द व्यापक रूप से उपयोग किया जाता है) - या "सिमेंटिक फैसिलिटी"।

उदाहरण: आपको वस्तुओं का प्रतिनिधित्व करने वाले वर्गों का एक समूह मिला है। आप कक्षा विधि all()या find()लिखने User.all()या करने के लिए चाहते हो सकता है User.find(firstname='Guido')। कि मॉड्यूल स्तर के कार्यों का उपयोग करके किया जा सकता है ...


आप उदाहरण देते हैं, निश्चित रूप से, कि वर्ग अपने सभी उदाहरणों पर नज़र रख रहा है और उनके निर्मित होने के बाद उन तक पहुंच बना सकता है - कुछ स्वचालित रूप से नहीं।
मार्टीन्यू

1
"सिमेंटिक शुगर" "सिंटैक्टिक शुगर" के लिए एक अच्छा मैच लगता है।
XTL

3

रूबी से आने पर मुझे जो कुछ मिला, वह यह है कि एक तथाकथित वर्ग पद्धति और एक तथाकथित उदाहरण विधि सिर्फ एक फ़ंक्शन है जिसका अर्थ है पहला पैरामीटर, जो चुपचाप पारित हो जाता है , जब फ़ंक्शन को विधि के रूप में कहा जाता है एक वस्तु (यानी obj.meth())।

आम तौर पर वह वस्तु एक उदाहरण होनी चाहिए, लेकिन @classmethod विधि सज्जाकार एक वर्ग को पारित करने के लिए नियमों को बदल देता है। आप उदाहरण के लिए एक वर्ग विधि कह सकते हैं (यह सिर्फ एक कार्य है) - पहला तर्क इसका वर्ग होगा।

क्योंकि यह केवल एक फ़ंक्शन है , इसे किसी भी दिए गए दायरे (यानी classपरिभाषा) में केवल एक बार घोषित किया जा सकता है । यदि इस प्रकार, रूबीवादी के लिए आश्चर्य की बात है, तो आपके पास एक वर्ग विधि और एक ही नाम के साथ एक आवृत्ति विधि नहीं हो सकती है

इस पर विचार करो:

class Foo():
  def foo(x):
    print(x)

आप fooएक उदाहरण पर कॉल कर सकते हैं

Foo().foo()
<__main__.Foo instance at 0x7f4dd3e3bc20>

लेकिन एक वर्ग पर नहीं:

Foo.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)

अब जोड़ें @classmethod:

class Foo():
  @classmethod
  def foo(x):
    print(x)

एक उदाहरण पर कॉल करना अब अपनी कक्षा से गुजरता है:

Foo().foo()
__main__.Foo

जैसे क्लास में कॉल करना:

Foo.foo()
__main__.Foo

यह केवल कन्वेंशन है जो यह बताता है कि हम selfउस पहले तर्क के लिए एक इंस्टेंस विधि और clsएक क्लास पद्धति पर उपयोग करते हैं। मैंने यहां न तो यह वर्णन करने के लिए उपयोग किया कि यह सिर्फ एक तर्क है। रूबी में, selfएक कीवर्ड है।

रूबी के साथ विपरीत:

class Foo
  def foo()
    puts "instance method #{self}"
  end
  def self.foo()
    puts "class method #{self}"
  end
end

Foo.foo()
class method Foo

Foo.new.foo()
instance method #<Foo:0x000000020fe018>

पायथन वर्ग विधि सिर्फ एक सजाया हुआ कार्य है और आप अपने स्वयं के सज्जाकार बनाने के लिए समान तकनीकों का उपयोग कर सकते हैं । एक सजाया विधि वास्तविक विधि को लपेटता है (इसके मामले में @classmethodअतिरिक्त कक्षा तर्क पास करता है)। अंतर्निहित विधि अभी भी है, छिपी हुई है लेकिन अभी भी सुलभ है


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


"जो चुपचाप पारित हो जाता है जब फ़ंक्शन को ऑब्जेक्ट की विधि के रूप में कहा जाता है" - मेरा मानना ​​है कि यह सटीक नहीं है। एएफआईसीटी, पायथन में "चुपचाप पारित" कुछ भी नहीं है। IMO, पायथन इस अर्थ में रूबी की तुलना में बहुत अधिक समझदार है (को छोड़कर super())। एएफआईसीटी, "जादू" तब होता है जब एक विशेषता सेट या पढ़ी जाती है। obj.meth(arg)पाइथन (रूबी के विपरीत) में कॉल का मतलब बस है (obj.meth)(arg)। कुछ भी चुपचाप कहीं भी पारित नहीं किया जाता है, obj.methबस एक कॉल करने योग्य वस्तु है जो उस फ़ंक्शन से कम एक तर्क को स्वीकार करता है जिससे इसे बनाया गया था।
एलेक्सी

obj.methबदले में, बस का मतलब है getattr(obj, "meth")
एलेक्सी

अन्य सामान्य भाषाओं से आने वाले लोगों के अनुरूप उत्तर देने के लिए समझ में आता है। हालाँकि, इस वार्तालाप से एक चीज़ गायब है, जो इसे एक साथ जोड़ती है, एक पायथन विवरणक की धारणा है । फ़ंक्शंस डिस्क्रिप्टर हैं , और यह है कि पहला तर्क "ऑटोमैटिकली" एक उदाहरण से गुजरता है जब एक फ़ंक्शन क्लास के लिए एक विशेषता है। यह भी है कि क्लासमेथोड कैसे लागू किया जाता है, और HOWTO I से जुड़ा एक शुद्ध अजगर कार्यान्वयन प्रदान किया जाता है। तथ्य यह है कि यह भी एक डेकोरेटर है सहायक की तरह है
juanpa.arrivillaga

2

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

इसे समझने के लिए यहाँ एक उदाहरण है। ध्यान दें कि सभी उदाहरणों में एकल शब्दकोश का संदर्भ है। यह फैक्ट्री पैटर्न नहीं है क्योंकि मैं इसे समझता हूं। यह शायद अजगर के लिए बहुत अनूठा है।

class M():
 @classmethod
 def m(cls, arg):
     print "arg was",  getattr(cls, "arg" , None),
     cls.arg = arg
     print "arg is" , cls.arg

 M.m(1)   # prints arg was None arg is 1
 M.m(2)   # prints arg was 1 arg is 2
 m1 = M()
 m2 = M() 
 m1.m(3)  # prints arg was 2 arg is 3  
 m2.m(4)  # prints arg was 3 arg is 4 << this breaks the factory pattern theory.
 M.m(5)   # prints arg was 4 arg is 5

2

मैं अपने आप से कुछ ही बार सवाल पूछ रहा था। और भले ही यहाँ के लोगों ने इसे समझाने की पूरी कोशिश की, IMHO सबसे अच्छा जवाब (और सबसे सरल) उत्तर जो मुझे मिला है वह पायथन डॉक्यूमेंटेशन में क्लास पद्धति का वर्णन है।

स्टैटिक विधि का भी संदर्भ है। और अगर कोई पहले से ही उदाहरण के तरीकों (जो मुझे लगता है) को जानता है, तो यह उत्तर अंतिम टुकड़ा हो सकता है कि यह सब एक साथ रखा जाए ...

इस विषय पर आगे और गहन विस्तार भी प्रलेखन में पाया जा सकता है: मानक प्रकार पदानुक्रम ( इंस्टेंट विधियों अनुभाग पर स्क्रॉल करें )


1

@classmethodबाहरी संसाधनों से उस वर्ग की वस्तुओं को आसानी से तात्कालिक बनाने के लिए उपयोगी हो सकता है। निम्नलिखित को धयान मे रखते हुए:

import settings

class SomeClass:
    @classmethod
    def from_settings(cls):
        return cls(settings=settings)

    def __init__(self, settings=None):
        if settings is not None:
            self.x = settings['x']
            self.y = settings['y']

फिर दूसरी फाइल में:

from some_package import SomeClass

inst = SomeClass.from_settings()

Inst.x पर पहुँचना सेटिंग ['x'] के समान मान देगा।


0

एक वर्ग निश्चित रूप से उदाहरणों के एक सेट को परिभाषित करता है। और एक वर्ग के तरीके अलग-अलग उदाहरणों पर काम करते हैं। कक्षा के तरीके (और चर) अन्य जानकारी को लटकाने के लिए एक जगह है जो सभी पर उदाहरणों के सेट से संबंधित है।

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

आप पूरे सेट पर काम करने के लिए उपकरणों को परिभाषित करने के लिए वर्ग विधियों का भी उपयोग कर सकते हैं। उदाहरण के लिए Student.all_of_em () सभी ज्ञात छात्रों को वापस कर सकता है। जाहिर है अगर आपके उदाहरणों के सेट में सिर्फ एक सेट की तुलना में अधिक संरचना है, तो आप उस संरचना के बारे में जानने के लिए कक्षा के तरीके प्रदान कर सकते हैं। Students.all_of_em (ग्रेड = 'जूनियर')

इस तरह की तकनीकें वर्ग चर में निहित डेटा संरचनाओं में इंस्टेंस के सेट के सदस्यों को संग्रहीत करने की ओर ले जाती हैं। फिर आपको कचरा संग्रह से निराश होने से बचने के लिए ध्यान रखने की आवश्यकता है।

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