2012-07-24 9 views
11

Ich überschreibe die __new__() Methode einer Klasse, um eine Klasseninstanz zurückzugeben, die eine bestimmte __init__() festgelegt hat. Python scheint die Klasse bereitgestellte __init__() Methode anstelle der instanzspezifischen Verfahren zu nennen, obwohl die Python-Dokumentation unterWarum ruft Python nicht die Instanzmethode __init __() zur Instanzerstellung auf, sondern ruft stattdessen die Klasse __init __() auf?

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

sagt:

Typische Implementierungen eine neue Instanz der Klasse erstellen, indem Rufen Sie die __new __() -Methode der Oberklassesuper auf (supercurrentclass, cls) .__ new __ (cls [, ...]) mit geeigneten Argumenten und modifizieren Sie dann die neu erstellte Instanz als , bevor Sie sie zurückgeben.

Wenn __new __() eine Instanz von cls zurückgibt, die __init __ die neue Instanz() -Methode wird wie __init __ aufgerufen werden (self [, ...]), wo sich die neue Instanz ist und die verbleibenden Argumente das gleiche wie an __new __() übergeben wurde.

Hier ist mein Testcode:

#!/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() 

die

gibt
$ 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 = {} 

es den einzigen Weg scheint, zu bekommen myinit() zu laufen ist es als self.__init__() innerhalb myclass.__init__() ausdrücklich zu nennen.

+1

Gute Frage! – Marcin

Antwort

8

Spezielle Methoden an neuen Stil Klassen betreut werden auf dem Typ der Instanz, nicht auf der Instanz selbst. Dies ist documented behaviour:

Für neuen Stil Klassen, implizite Anrufungen spezieller Methoden sind nur dann korrekt arbeiten gewährleistet, wenn auf einer Objekttyp definiert, nicht in der Instanz Wörterbuch des Objekts.Dieses Verhalten ist der Grund, warum der folgende Code eine Ausnahme auslöst (im Gegensatz zu dem äquivalenten Beispiel mit altem Stil-Klassen):

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

Verschiedene spezielle Methoden (einschließlich __init__, aber auch Bedienerüberladungen wie __add__ usw.) sind always accessed via the class rather than the instance. Nicht nur das, aber sie können nicht über eine __getattr__ oder __getattribute__ Methode für die Klasse oder Metaklasse zugegriffen werden, sie müssen direkt in der Klasse sein. Dies ist aus Gründen der Effizienz:

Umgehen die __getattribute__() Maschinen auf diese Weise bietet erheblichen Spielraum für die Geschwindigkeitsoptimierungen innerhalb des Dolmetschers, auf Kosten einer gewissen Flexibilität im Umgang mit speziellen Methoden (die spezielle Methode festgelegt werden muss das Klassenobjekt selbst, um vom Interpreter konsistent aufgerufen zu werden).

Es ist nicht ganz klar, was Sie erreichen wollen, aber eine Sache, die Sie hier tun können, ist myclass innerhalb der __new__ Methode Unterklasse:

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) 
Verwandte Themen