Hãy để tôi bắt đầu với điều này không phải là lặp lại của Why does __init__ not get called if __new__ called with no args. Tôi đã cố gắng xây dựng cẩn thận một số mã mẫu cho __new__
và __init__
mà không có lời giải thích nào tôi có thể tìm thấy.Tại sao __init__ không được gọi sau __new__ SOMETIMES
Các thông số cơ bản:
- Có một lớp cơ sở gọi là NotMine vì nó xuất phát từ một thư viện (Tôi sẽ tiết lộ ở cuối, không quan trọng ở đây)
- lớp đó có một phương pháp
__init__
rằng lần lượt gọi một phương pháp_parse
- tôi cần phải ghi đè lên các phương pháp
_parse
trong lớp con - mà lớp con tôi là tạo ra không biết cho đến khi gọi
- Tôi biết có những phương pháp thiết kế nhà máy nhưng tôi không thể sử dụng chúng ở đây (Xem thêm ở cuối)
- Tôi đã cố gắng để tận dụng cẩn thận của
super
để tránh các vấn đề trong Python logging: Why is __init__ called twice? - Tôi biết điều này cũng là 'loại 'cơ hội AbstractBaseMehtod nhưng điều đó không giúp
Dù sao, __init__
nên được gọi sau __new__
và cho mọi giải thích về lý do tại sao một số mẫu dưới đây không làm việc tôi dường như để có thể trỏ đến các trường hợp khác mà làm việc và loại trừ lời giải thích.
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
Nếu bạn thực thi mã, bạn có thể thấy rằng đối với mỗi cuộc gọi đến __new__
nó thông báo "mà cửa" nó được thoát qua và với những gì loại. Tôi có thể thoát khỏi cùng một "cửa" với cùng một loại "" đối tượng và có __init__
được gọi là trong một trường hợp và không phải là khác. Tôi đã nhìn vào mro của lớp "gọi" và cung cấp không có cái nhìn sâu sắc kể từ khi tôi có thể gọi lớp đó (hoặc một subcass như trong CCC) và có __init__
gọi.
End Ghi chú: Các NotMine
thư viện Tôi đang sử dụng là Genshi MarkupTemplate và lý do không sử dụng một phương pháp thiết kế Nhà máy là TemplateLoader họ cần một defaultClass để xây dựng. Tôi không biết cho đến khi tôi bắt đầu phân tích cú pháp, điều tôi làm trong __new__
. Có rất nhiều ma thuật voodoo mát mẻ mà genshi bộ nạp và các mẫu làm điều đó có giá trị nỗ lực này.
Tôi có thể chạy một phiên bản chưa được sửa đổi của trình tải của họ và hiện tại mọi thứ đều hoạt động miễn là tôi CHỈ vượt qua lớp ABC (lớp sắp xếp theo kiểu trừu tượng) làm mặc định. Mọi thứ đang hoạt động tốt nhưng hành vi không giải thích được này là một lỗi gần như chắc chắn sau đó.
UPDATE: Ignacio, đóng đinh câu hỏi dòng trên cùng, nếu đối tượng quay trở lại không phải là một "thể hiện của" cls sau đó __init__
không được gọi. Tôi thấy rằng gọi là "constructor" (ví dụ như AA(args..)
là sai vì nó sẽ gọi __new__
một lần nữa và bạn quay lại ngay nơi bạn bắt đầu. Bạn có thể sửa đổi một arg để có một con đường khác. Điều đó có nghĩa là bạn gọi ABC.__new__
hai lần thay vì vô hạn .Giải pháp làm việc là chỉnh sửa class ABC
ở trên là:
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
Lưu ý một vài dòng cuối cùng. Không gọi __init__
nếu đó là một lớp "khác" không có ý nghĩa với tôi, ĐẶC BIỆT khi lớp "khác" vẫn là lớp con của lớp gọi là __init__
. Tôi không thích các chỉnh sửa ở trên nhưng ít nhất tôi nhận được các quy tắc tốt hơn một chút ngay bây giờ.
Genshi có sử dụng metaclass không? Xem http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python – Borealid
Không, Mã mẫu của tôi không sử dụng genshi làm cơ sở. –