Позвольте мне начать с этого не повторение Why does __init__ not get called if __new__ called with no args. Я попытался тщательно построить образец кода для __new__
и __init__
, который не имеет объяснений, которые я могу найти.Почему __init__ не вызывается после __new__ ИНОГДА
Основные параметры:
- Существует базовый класс называется NotMine, как это происходит из другой библиотеки (я буду раскрывать в конце концов, не важно)
- Этот класс имеет
__init__
метод, в свою очередь, называет_parse
метод - мне нужно переопределить метод
_parse
в подклассах - который подкласс Я создаю не известно до вызова
- Я знаю, что есть методы проектирования завода, но я не могу использовать их здесь (Подробнее в конце)
- Я попытался сделать бережное использование
super
, чтобы избежать проблем в Python logging: Why is __init__ called twice? - Я знаю, что это также «вид 'возможность AbstractBaseMehtod, но это не помогло
Во всяком случае, __init__
должен быть вызван после __new__
и для каждого объяснения того, почему некоторые образцы ниже не работают, я, кажется, быть в состоянии указать на другие случаи, которые делают работу и исключить объяснение.
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
Если выполнить код, вы можете увидеть, что для каждого вызова __new__
он объявляет «какой дверь» она выходит через и с каким типом. Я могу выйти из той же «двери» с тем же «типом» объекта и вызвать __init__
в одном случае, а не в другом. Я посмотрел на mro класса «call», и это не дает понимания, поскольку я могу вызвать этот класс (или подкасс как в CCC) и вызвал __init__
.
Конец Примечания: NotMine
библиотека Я использую является Genshi MarkupTemplate и причина не используя метод проектирования завода является то, что их TemplateLoader нуждается в defaultClass построить. Я не знаю, пока не начну синтаксический анализ, что я делаю в __new__
. Существует много классной волшебной магии вуду, что genshi загрузчики и шаблоны делают это стоит усилий.
Я могу запустить немодифицированный экземпляр своего загрузчика, и в настоящее время все работает до тех пор, пока я ТОЛЬКО передаю класс ABC (абстрактный сортировочный завод) по умолчанию. Все работает хорошо, но это необъяснимое поведение является почти определенной ошибкой позже.
UPDATE: Игнасио, прибил вопрос верхней строки, если возвращаемый объект не является «экземпляр» ЦБСА тогда __init__
не называется. Я нахожу, что вызов «конструктора» (например, AA(args..)
ошибочен, так как он снова вызовет __new__
, и вы вернетесь туда, где вы начали. Вы можете изменить аргумент, чтобы выбрать другой путь. Это просто означает, что вы вызываете ABC.__new__
дважды, а не бесконечно ,Рабочий раствор для редактирования class ABC
выше, как:
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
Обратите внимание на последние несколько строк. Не вызывать __init__
, если это «другой» класс, для меня не имеет смысла, ОСОБЕННО, когда «другой» класс по-прежнему является подклассом класса, вызывающего __init__
. Мне не нравятся приведенные выше изменения, но, по крайней мере, я немного поправляю правила.
Является ли Генши использованием метакласса? См. Http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python – Borealid
Нет, мой пример кода не использует genshi в качестве базы. –