Zacznę od tego, że nie jest to powtórka z Why does __init__ not get called if __new__ called with no args. Próbowałem starannie zbudować przykładowy kod dla __new__
i __init__
, który nie ma wyjaśnienia, które mogę znaleźć.Dlaczego __init__ nie jest wywoływane po __new__ SOMETIMES
Podstawowe parametry:
- Istnieje klasa bazowa nazywana NotMine gdyż pochodzi z innej biblioteki (będę ujawniać na końcu, nie ważne tutaj)
- To klasa ma metodę
__init__
że z kolei nazywa_parse
metoda - muszę zastąpić metodę w podklasach
_parse
- których podklasa tworzę nie jest znany aż do wywołania
- wiem, że istnieją metody projektowania fabryki, ale nie mogę ich używać tutaj (Więcej na końcu)
- Próbowałem dokonać starannego wykorzystania
super
aby uniknąć problemów w Python logging: Why is __init__ called twice? - wiem, że to też „niby "okazją AbstractBaseMehtod ale to nie pomogło
Zresztą __init__
powinny być nazywane po __new__
i za każdym wyjaśnieniem, dlaczego niektóre próbki poniżej nie działają wydaje mi się, aby móc zwrócić się do innych przypadków, które wykonują pracę i wykluczyć wyjaśnienie.
class NotMine(object):
def __init__(self, *args, **kwargs):
print "NotMine __init__"
self._parse()
def _parse(self):
print "NotMine _parse"
class ABC(NotMine):
def __new__(cls,name,*args, **kwargs):
print "-"*80
print "Entered through the front door ABC.__new__(%s,%s,*%s,**%s)"%(cls,name,args,kwargs)
if name == 'AA':
obj = super(NotMine,ABC).__new__(AA,*args,**kwargs)
print "Exiting door number 1 with an instance of: %s"%type(obj)
return obj
elif name == 'BB':
obj = super(NotMine,ABC).__new__(BB,*args,**kwargs)
print "Exiting door number 2 with an instance of: %s"%type(obj)
return obj
else:
obj = super(NotMine,ABC).__new__(cls,*args,**kwargs)
print "Exiting door number 3 with an instance of: %s"%type(obj)
return obj
class AA(ABC):
def _parse(self):
print "AA _parse"
class BB(ABC):
def __init__(self, *args, **kw):
print "BB_init:*%s, **%s"%(args,kw)
super(BB,self).__init__(self,*args,**kw)
def _parse(self):
print "BB _parse"
class CCC(AA):
def _parse(self):
print "CCCC _parse"
print("########### Starting with ABC always calls __init__ ############")
ABC("AA") # case 1
ABC("BB") # case 2
ABC("NOT_AA_OR_BB") # case 3
print("########### These also all call __init__ ############")
AA("AA") # case 4
BB("BB") # case 5
AA("NOT_AA_OR_BB") # case 6
BB("NOT_AA_OR_BB") # case 7
CCC("ANYTHING") # case 8
print("########### WHY DO THESE NOT CALL __init__ ############")
AA("BB") # case 9
BB("AA") # case 10
CCC("BB") # case 11
Jeśli wykonanie kodu, można zobaczyć, że dla każdego wywołania __new__
zapowiada „który door” jest wyjściem poprzez iz jakiego typu. Mogę wyjść z tych samych "drzwi" z tego samego obiektu "typu" i mieć __init__
w jednym przypadku, a nie w drugim. Spojrzałem na mro z klasy "calling" i nie oferuje mi wglądu, ponieważ mogę wywołać tę klasę (lub podklas jak w CCC) i wywołać __init__
.
End Uwagi: NotMine
biblioteki używam jest Genshi MarkupTemplate i powód nie stosując metodę projektowania Factory to, że ich TemplateLoader potrzebuje defaultClass skonstruować. Nie wiem, dopóki nie rozpocznie się parsowanie, co robię w __new__
. Istnieje wiele fajnych magii voodoo, które obsługują ładowarki i szablony genshi, co czyni ten wysiłek wartym wysiłku.
Mogę uruchomić niezmodyfikowaną instancję swojego programu ładującego, a obecnie wszystko działa tak długo, jak TYLKO przekazuję klasę ABC (abstrakcyjne sortowanie fabryczne) jako domyślną. Wszystko działa dobrze, ale to niewyjaśnione zachowanie jest prawie pewnym błędem później.
UPDATE: Ignacio, przybity górnym wierszu pytanie, czy zwrócony obiekt nie jest „przypadkiem” CLS następnie __init__
nie jest tzw. Uważam, że wywołanie "konstruktora" (np. AA(args..)
jest nieprawidłowe, ponieważ będzie ono wywoływać ponownie __new__
i jesteś z powrotem tam, gdzie zacząłeś.Możesz zmodyfikować argument, aby wybrać inną ścieżkę.To oznacza, że dwa razy zamiast wywołać ABC.__new__
, a nie bez końca .Roztwór roboczy jest edycja class ABC
powyżej jako:
class ABC(NotMine):
def __new__(cls,name,*args, **kwargs):
print "-"*80
print "Entered through the front door ABC.__new__(%s,%s,*%s,**%s)"%(cls,name,args,kwargs)
if name == 'AA':
obj = super(NotMine,ABC).__new__(AA,*args,**kwargs)
print "Exiting door number 1 with an instance of: %s"%type(obj)
elif name == 'BB':
obj = super(NotMine,ABC).__new__(BB,*args,**kwargs)
print "Exiting door number 2 with an instance of: %s"%type(obj)
elif name == 'CCC':
obj = super(NotMine,ABC).__new__(CCC,*args,**kwargs)
print "Exiting door number 3 with an instance of: %s"%type(obj)
else:
obj = super(NotMine,ABC).__new__(cls,*args,**kwargs)
print "Exiting door number 4 with an instance of: %s"%type(obj)
## Addition to decide who calls __init__ ##
if isinstance(obj,cls):
print "this IS an instance of %s So call your own dam __init__"%cls
return obj
print "this is NOT an instance of %s So __new__ will call __init__ for you"%cls
obj.__init__(name,*args, **kwargs)
return obj
print("########### now, these DO CALL __init__ ############")
AA("BB") # case 9
BB("AA") # case 10
CCC("BB") # case 11
Wskazówka ostatnie kilka linii. Nie wywoływanie __init__
, jeśli jest to "inna" klasa, nie ma dla mnie sensu, SZCZEGÓLNIE, gdy "inna" klasa nadal jest podklasą klasy wywołującej __init__
. Nie podoba mi się powyższa edycja, ale przynajmniej teraz mam nieco lepsze zasady.
Czy Genshi używa metaclass? Zobacz http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python – Borealid
Nie, Mój przykładowy kod nie używa genshi jako bazy. –