2012-07-24 15 views
11

मैं कक्षा के उदाहरण को वापस करने के लिए कक्षा के __new__() विधि को पार कर रहा हूं जिसमें विशिष्ट __init__() सेट है। अजगरउदाहरण के निर्माण पर पायथन कॉल इंस्टेंस विधि __init __() क्यों नहीं है बल्कि क्लास-प्रदान किए गए __init __() को कॉल करता है?

http://docs.python.org/reference/datamodel.html

में, उदाहरण के विशेष विधि के बजाय वर्ग-प्रदान की __init__() विधि कॉल करने हालांकि अजगर प्रलेखन लगता है कहते हैं:

विशिष्ट कार्यान्वयन से वर्ग का एक नया उदाहरण बनाने सुपर (वर्तमान क्लास, सीएलएस) का उपयोग कर सुपरक्लास की __new __() विधि का उपयोग करना .__ नया __ (सीएलएस [, ...]) उचित तर्क के साथ और फिर इसे बनाए जाने से पहले के रूप में नव निर्मित उदाहरण को संशोधित करना।

__new __() cls का एक उदाहरण देता है, तो उसके बाद नया उदाहरण के __init __() विधि __init __ तरह सक्रिय किया जाएगा (स्वयं [...]), जहां स्वयं नया उदाहरण है और शेष तर्क हैं जैसा कि __new __() को पास किया गया था।

यहाँ अपने परीक्षण कोड है:

#!/usr/bin/env python 

import new 

def myinit(self, *args, **kwargs): 
    print "myinit called, args = %s, kwargs = %s" % (args, kwargs) 


class myclass(object): 
    def __new__(cls, *args, **kwargs): 
     ret = object.__new__(cls) 

     ret.__init__ = new.instancemethod(myinit, ret, cls) 
     return ret 

    def __init__(self, *args, **kwargs): 
     print "myclass.__init__ called, self.__init__ is %s" % self.__init__ 
     self.__init__(*args, **kwargs) 

a = myclass() 

जो

$ python --version 
Python 2.6.6 
$ ./mytest.py 
myclass.__init__ called, self.__init__ is <bound method myclass.myinit of <__main__.myclass object at 0x7fa72155c790>> 
myinit called, args =(), kwargs = {} 

आउटपुट यह myinit() चलाने के लिए प्राप्त करने के लिए एक ही रास्ता लगता है self.__init__()myclass.__init__() अंदर के रूप में स्पष्ट रूप से इसे कॉल करने के लिए है।

+1

महान प्रश्न: यह व्यवहार कारण है कि निम्नलिखित कोड (पुरानी शैली वर्गों के साथ बराबर उदाहरण के विपरीत) एक अपवाद को जन्म देती है! – Marcin

उत्तर

8

नई शैली वर्गों पर विशेष तरीकों उदाहरण के प्रकार पर, उदाहरण पर नहीं। यह documented behaviour है:

नई शैली कक्षाओं के लिए, विशेष तरीकों की अंतर्निहित आमंत्रण केवल सही ढंग से काम करने के लिए है, एक वस्तु के प्रकार पर परिभाषित वस्तु का उदाहरण शब्दकोश में नहीं की गारंटी है।

>>> class C(object): 
...  pass 
... 
>>> c = C() 
>>> c.__len__ = lambda: 5 
>>> len(c) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: object of type 'C' has no len() 
8

विभिन्न विशेष तरीकों (__init__ सहित, लेकिन ऑपरेटर ओवरलोड जैसे __add__, आदि) always accessed via the class rather than the instance हैं। इतना ही नहीं, लेकिन उन्हें कक्षा या मेटाक्लास पर __getattr__ या __getattribute__ विधि के माध्यम से एक्सेस नहीं किया जा सकता है, उन्हें सीधे कक्षा में होना है।

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

यह पूरी तरह स्पष्ट आप क्या हासिल करने की कोशिश कर रहे हैं नहीं है, लेकिन एक बात तुम यहाँ क्या कर सकता है __new__ विधि के भीतर myclass उपवर्ग के लिए है: देखा जाता है

class myclass(object): 
    def __new__(cls, *args, **kwargs): 
     class subcls(cls): 
      def __new__(cls, *args, **kwargs): 
       return object.__new__(cls) 
     subcls.__init__ = myinit 
     return subcls(*args, **kwargs)