Niyə __init __ () hər zaman __new __ () sonra çağırılır?

Mən yalnız dərslərimdən birini düzəltməyə çalışıram və sinif dizaynı ilə eyni stildə bəzi funksiyaları təqdim etmişəm.

Ancaq __init__ zaman __new__ sonra niyə __init__ bir az qarışdırdım. Bunu gözləmirdim. Hər kəsin bu niyə baş verdiyini mənə söyləyə bilərəm və bu funksiyanı başqa şəkildə necə həyata keçirə bilərəm? ( __new__ olduqca hacked görünür __new__ həyata keçirilir ki, __new__ .)

Burada bir nümunə:

 class A(object): _dict = dict() def __new__(cls): if 'key' in A._dict: print "EXISTS" return A._dict['key'] else: print "NEW" return super(A, cls).__new__(cls) def __init__(self): print "INIT" A._dict['key'] = self print "" a1 = A() a2 = A() a3 = A() 

Çıxışlar:

 NEW INIT EXISTS INIT EXISTS INIT 

Niyə?

447
23 марта '09 в 20:13 2009-03-23 20:13 Dan 23 Mart 'da saat 20 : 13-da təyin olundu, 2009-03-23 ​​20:13
@ 17 cavab

Yeni bir nümunənin yaradılmasını idarə etmək üçün __ yeni __ istifadə edin. Yeni bir nümunənin başlanmasını idarə etməli olduğunuzda __ init __ istifadə edin.

__ yeni __ bir nümunə yaratmanın ilk addımıdır. Bu, ilk olaraq adlanır və sinifin yeni bir nümunəsini qaytarmaq üçün məsuliyyət daşıyır. Əksinə, __ init __ heç bir şey qaytarır; o, yaradıldıqdan sonra yalnız başlanğıc üçün məsuliyyət daşıyır.

Ümumiyyətlə, str, int, unicode, ya da tuple alt sinifləşdirilməmiş halda __ new __- ə qüvvədə saxlamağa ehtiyac yoxdur.

Kimdən: http://mail.python.org/pipermail/tutor/2008-April/061426.html

Bunu etməyə çalışdığınız şey, ümumiyyətlə, Fabrika ilə həyata keçirilir və bunun ən yaxşı üsuludur. Yeni __ __ istifadə edərək təmiz bir həll deyil, belə ki, zavoddan istifadə edin. İşdə yaxşı bir fabrik nümunəsi .

473
23 марта '09 в 20:23 2009-03-23 20:23 Cavab mpeterson tərəfindən 23 mart '09 saat 20:23 'də verilir. 2009-03-23 ​​20:23

__new__ statik sinif üsuludur və __init__ bir nümunə üsuludur. __new__ əvvəlcə bir nümunə yaratmalı, belə ki __init__ onu işə __init__ bilər. __init__ parametrinin self __init__ unutmayın. Bir nümunə meydana gətirmədiyinizə qədər, self bir şey yoxdur.

İndi mən başa düşürəm ki, Pythonda bir tək nümunə tətbiq etməyə çalışırsınız. Bunun bir çox yolu var.

border=0

Bundan əlavə, Python 2.6 ilə dekorativlərdən istifadə edə bilərsiniz.

 def singleton(cls): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls() return instances[cls] return getinstance @singleton class MyClass: ... 
146
23 марта '09 в 20:20 2009-03-23 20:20 Cavab vartec 23 mart 'da 20:20' də verilir. 2009-03-23 ​​20:20

Ən tanınmış dillərdə, bəzi SomeClass(arg1, arg2) ifadəsi SomeClass(arg1, arg2) yeni bir nümunə ayırır SomeClass(arg1, arg2) atributlarını işə salır və sonra qaytarır.

Ən tanınmış dillərdə, OO öznitəsindəki "nümunə atributlarını başlatmaq" hər bir sinif üçün konstruktorun əsasən hər hansı bir başlanğıc şəraiti yaratmaq üçün yeni instansiyada işləyən bir kod blokudur (konstruktiv ifadəyə verilən mülahizələri istifadə etməklə). Python'da, bu __init__ sinfi metoduna __init__ .

Python __new__ , sinifin oxşar bir özelleştirilmesinden başqa bir şey deyil "yeni bir nümunə ayırmaq". Əlbəttə ki, bu, yeni bir məqamı vurğulamaq deyil, mövcud bir nümunəni qaytarmaq kimi qeyri-adi şeylər etməyə imkan verir. Buna görə də, Python'da, bu hissəni qaçınılmaz olaraq dağıtma ilə əlaqəli olaraq düşünməməliyik; biz lazım olan bütün __new__ bir yerdə müvafiq instansiya görünür.

Amma bu, yalnız yarım vəzifədir və Python sisteminin bəzən vəzifənin ikinci yarısını ( __init__ ) idarə etmək istədiyini və bəzən bilməyəcəyini __init__ üçün bir yol yoxdur. Bu davranışı istəyirsinizsə, bunu açıq şəkildə söyləmək lazımdır.

Tez-tez yenidən təşkil edə bilərsiniz, belə ki, yalnız __new__ lazımdır və ya __new__ ehtiyac __new__ , və ya __init__ artıq başlamış bir obyekt üzərində fərqli davranır. Amma əgər bu həqiqətən SomeClass(arg1, arg2) , Python "Task" i yenidən müəyyən etməyə imkan verir, belə ki SomeClass(arg1, arg2) mütləq __new__ və sonra __init__ . Bunu etmək üçün bir metaclass yaratmaq və __call__ metodunu müəyyən etmək lazımdır.

Metaclass yalnız bir sinif sinifidir. Sinif metodu __call__ sinif __call__ nə olur. Beləliklə, ' __call__ ' metaclassı bir sinif çağırdığınız zaman nə olacağını nəzarət edir; yəni, bir nümunəni başdan sona qədər yaratmaq mexanizmini ləğv etməyə imkan verir. Bu bir tək nümunə nümunəsi kimi tamamilə standart olmayan bir instansiya yaradılması prosesini ən zərif şəkildə tətbiq edə biləcəyiniz səviyyədir. Əslində, kodun 10 xəttindən az olan, Singleton sinifinin metaslasını tətbiq edə bilərsiniz, sonra da __new__ ilə heç bir futz tələb etməyəcək və sadəcə __metaclass__ = Singleton əlavə edərək adi bir klassı tək elementə __metaclass__ = Singleton !

 class Singleton(type): def __init__(self, *args, **kwargs): super(Singleton, self).__init__(*args, **kwargs) self.__instance = None def __call__(self, *args, **kwargs): if self.__instance is None: self.__instance = super(Singleton, self).__call__(*args, **kwargs) return self.__instance 

Lakin bu, bu vəziyyət üçün həqiqətən haqlı olduğundan daha dərin sehrdir!

124
29 дек. cavab verildi 2011-12-29 10:39 '12 at 10:39 2011-12-29 10:39

Sitat gətirən sənədlər :

Tipik tətbiqlər müvafiq sübutlarla "super (currentclass, cls) .__ new __ (cls [, ...])" istifadə edərək superclass metodunu __new __ () çağıraraq sinifin yeni bir nümunəsini yaradır və lazım olduqda yeni yaradılmış onu qaytarmadan əvvəl surəti.

...

Əgər __new __ () bir cls nümunəsini qaytarmasa, yeni __init __ () metodu çağrılmayacaqdır.

__n __ (), əsasən, dəyişikliklərin alt sinifləri üçün nəzərdə tutulub (məsələn, int, str və ya tuple).

20
23 марта '09 в 20:29 2009-03-23 20:29 Cavab 23 Mart '09 saat 20: 29-da verilir. 2009-03-23 ​​20:29

Anladım ki, bu sual kifayət qədər köhnədir, amma buna bənzər bir problemim var idi. Aşağıdakılar istəmişəm:

 class Agent(object): _agents = dict() def __new__(cls, *p): number = p[0] if not number in cls._agents: cls._agents[number] = object.__new__(cls) return cls._agents[number] def __init__(self, number): self.number = number def __eq__(self, rhs): return self.number == rhs.number Agent("a") is Agent("a") == True 

Bu səhifəni resurs kimi istifadə etdim. Http://infohost.nmt.edu/tcc/help/pubs/python/web/new-new-method.html

10
13 мая '13 в 17:12 2013-05-13 17:12 Cavab Tobias'a 13 May '13, 5:12 'də verilir 2013-05-13 17:12

Bu sualın sadə cavabı, əgər __new__ eyni tipli bir dəyəri qaytarırsa, __init__ funksiyasını yerinə yetirir, əks halda bu olmaz. Bu halda, A._dict('key') cls ilə eyni sinif olan A._dict('key') qaytarır, belə ki __init__ yerinə yetiriləcək.

8
07 июля '13 в 17:45 2013-07-07 17:45 Cavab PMN 07 iyul '17 saat 17: 45-da verilir 2013-07-07 17:45

__new__ eyni sinfin bir nümunəsini qaytarır, __init__ qaytarılmış obyektdən sonra başlayır. Yəni, __new__ __init__ nin qaçışını qarşısını almaq üçün __init__ istifadə edə bilməzsiniz. Əvvəllər yaradılan bir obyekti __new__ dən __new__ , iki dəfə (üçlü, və s.), Yenidən __init__ təkrar olacaq.

Burada yuxarıdakı cavabı genişləndirən və düzəldən Singleton modelinə ümumi yanaşma:

 def SingletonClass(cls): class Single(cls): __doc__ = cls.__doc__ _initialized = False _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Single, cls).__new__(cls, *args, **kwargs) return cls._instance def __init__(self, *args, **kwargs): if self._initialized: return super(Single, self).__init__(*args, **kwargs) self.__class__._initialized = True # Its crucial to set this variable on the class! return Single 

Burada tam hekayə.

__new__ ki, __new__ daxil olan başqa bir yanaşma __new__ istifadə etməkdir:

 class Singleton(object): __initialized = False def __new__(cls, *args, **kwargs): if not cls.__initialized: cls.__init__(*args, **kwargs) cls.__initialized = True return cls class MyClass(Singleton): @classmethod def __init__(cls, x, y): print "init is here" @classmethod def do(cls): print "doing stuff" 

Bu yanaşma ilə bütün üsullarınızı @classmethod ilə @classmethod , çünki heç bir real MyClass nüsxəsini istifadə etməyəcəksiniz.

8
27 янв. Cavab Zaar Hai 27 Yanvar verilir 2015-01-27 00:25 '15 'də 0:25 2015-01-27 00:25
 class M(type): _dict = {} def __call__(cls, key): if key in cls._dict: print 'EXISTS' return cls._dict[key] else: print 'NEW' instance = super(M, cls).__call__(key) cls._dict[key] = instance return instance class A(object): __metaclass__ = M def __init__(self, key): print 'INIT' self.key = key print a1 = A('aaa') a2 = A('bbb') a3 = A('aaa') 

çıxışlar:

 NEW INIT NEW INIT EXISTS 

NB Yan təsirin M._dict olaraq M._dict avtomatik olaraq A._dict kimi A dan əldə edilə bilər, buna görə qəza ilə A._dict üçün diqqətli olun.

4
30 июля '15 в 15:04 2015-07-30 15:04 Cavab Antony Hatchkins tərəfindən 30 İyul, '15 'də 15:04' də verilir

__ new__ yeni boş sinif nümunəsini qaytarmalıdır. Sonra bu nümunəni başlatmaq üçün __init__ çağırılır. __New__ halda "YENİ" halda __init__ deyil, bu çağırılır. __new__ adlı kodu kodu __new__ __-nin müəyyən bir vəziyyətdə olub-olmadığını __new__ etmir və olmadıqda, burada çox qeyri-adi bir şey etdiyiniz üçün kodu.

__İnit__ funksiyasından bir obyektə bir atribut əlavə edə bilərsiniz ki, bu başlanıldığını göstərmək üçün. Bu xüsusiyyətin mövcudluğunu __init__-dəki ilk şey olaraq yoxlayın və əgər daha çox davam etsəniz.

4
23 марта '09 в 20:23 2009-03-23 20:23 Cavab Andrew Wilkinson tərəfindən 23 Mart 'da 20:23' də verildi. 2009-03-23 ​​20:23

Bu sənədə toxunaraq :

Nömrələr və strings kimi dəyişkən daxili növləri, bəzən digər vəziyyətlərdə subclassing zaman, yeni bir statik metod rahat formada görünür. Yeni , initdən əvvəl deyilən bir nümunə hazırlamaqda ilk addır .

Yeni üsul, birinci arqument kimi siniflə çağırılır; Onun məsuliyyəti bu sinifin yeni bir nümunəsini qaytarmaqdır.

Bunu init ilə müqayisə edin: init ilk instansiya kimi nümunə ilə çağırılır və heç bir şey qaytarır; məsuliyyəti məsələnin başlanmasını təmin etməkdir.

Yeni bir nümunənin init'i çağırmadan yaratdıqları hallar var (məsələn, bir nümunə brindən yüklənir). Yeni bir çağırış etmədən yeni bir nümunə yarada bilməzsiniz (baxmayaraq ki, bəzi hallarda əsas sinifə yeni bir çağrı ilə buraxa bilərsiniz).

Nə əldə etmək istədiyinizi, eyni zamanda, təkrarlanan birləşmə məlumatını.

 class Singleton(object): def __new__(cls, *args, **kwds): it = cls.__dict__.get("__it__") if it is not None: return it cls.__it__ = it = object.__new__(cls) it.init(*args, **kwds) return it def init(self, *args, **kwds): pass 

dekoratordan istifadə edərək PEP 318-dən bu tətbiqdən istifadə edə bilərsiniz

 def singleton(cls): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls() return instances[cls] return getinstance @singleton class MyClass: ... 
3
30 сент. Cavab cümə axşamı verilir 30 Sentyabr. 2013-09-30 09:13 '13 at 9:13 2013-09-30 09:13

@AntonyHatchkins üçün yeniləmə cavab verəcəkdir, yəqin ki, hər bir sinif sinfi üçün nümunələrin ayrı bir lüğətinə ehtiyacınız var, __init__ bütün siniflərdə qlobal olaraq bu __init__ istifadə edərək, sinfi obyektin sinif obyektini işə __init__ üçün __init__ metoduna sahib olmalısınız.

 class MetaQuasiSingleton(type): def __init__(cls, name, bases, attibutes): cls._dict = {} def __call__(cls, key): if key in cls._dict: print('EXISTS') instance = cls._dict[key] else: print('NEW') instance = super().__call__(key) cls._dict[key] = instance return instance class A(metaclass=MetaQuasiSingleton): def __init__(self, key): print 'INIT' self.key = key print() 

Mən __init__ üsulu ilə mənbə kodunu __init__ və Python 3 notasına sintaksisini dəyişdirdim ( super və metaclass üçün atributu deyil, sinif arqumentləri üçün no- __init__ ).

Hər halda, sinif başlatma ( __call__ metodu) __new__ və ya __init__ qeyd etmək vacibdir. __new__ istifadə edərək daha çox təmizdir, siz __init__ addım atlamaq istəyirsinizsə, obyekti qeyd etmək istədiyiniz.

3
18 июля '17 в 22:39 2017-07-18 22:39 Cavab Mad Physicist tərəfindən 18 iyul '17' də 10:39 2017-07-18 22:39 'də verilir

Bir az daha dərin qazma!

type , CPython tipindəki ümumi sinifdir və onun əsas sinfi obyektdir (meta sinif kimi başqa bir əsas sinfi açıq şəkildə müəyyən etmədiyiniz təqdirdə). Aşağı səviyyəli zənglərin ardıcıllığı burada tapa bilərsiniz . Birinci üsul çağırır tp_new , sonra tp_init və sonra tp_init çağırır.

Burada maraqlı bir hissə tp_new obyektin yaddaşına ayırdığı tp_alloc ( PyType_GenericAlloc ) yerinə yetirən tp_alloc yeni Object metodunu (əsas sinif) object_new

Bu nöqtədə, obyekt yaddaşda yaradılır və sonra __init__ metodu çağırılır. __init__ sizin sinifdə tətbiq __init__ , o zaman object_init çağırır və heç bir şey yoxdur :)

Sonra type_call sadəcə type_call bağlı olan obyekti qaytarır.

3
15 нояб. cavab verildi xpapazaf 15 noyabr. 2016-11-15 23:47 '16 saat 11:47 2016-11-15 23:47

Initdə ənənəvi OO dillərində sadə bir konstruktorun necə olduğunu nəzərdən keçirmək lazımdır. Məsələn, Java və ya C ++ ilə tanış olsanız, konstruktor dolandırıcıya öz instansiyasına ötürülür. Java halda, bu "bu" dəyişəndir. Kimsə Java üçün yaradılan bayt kodunu yoxsa, birinə iki zəng gəldi. İlk çağırış "yeni" üsuldur, sonra növbəti çağırış (bu, istifadəçi müəyyən konstruktorun əsl çağırışıdır). Bu iki addımlı proses, bu instansiyanın başqa bir üsulu olan sinif konstruktor metodunu çağırmadan əvvəl faktiki bir nümunə yaratmağa imkan verir.

İndi, Python halda yeni bir istifadəçi üçün əlavə bir xüsusiyyətdir. Java, yazılı xarakterinə görə bu rahatlığı təmin etmir. Dil bu qurğu təmin edərsə, yeni geliştirici yeni hallarda hər hansı bir halda əlaqəsiz bir obyektin tamamilə yeni bir nümunəsini yaratmaq da daxil olmaqla, bu metodda çox şey edə bilər. Və bu yanaşma da Python iddiasında dəyişməz tiplər üçün xüsusi bir şəkildə yaxşı işləyir.

3
24 апр. 24 Apreldə Guru Devanla tərəfindən cavab verildi 2014-04-24 04:30 '14, 4:30 'da 2014-04-24 04:30

__init__ sonra __new__ , belə ki, bir alt __new__ override zaman, əlavə kod hələ də çağırılacaq.

Əgər artıq __new__ olan bir sinfi alt sinif etməyə __new__ , bu barədə bilməyən kimsə __init__ uyğunlaşaraq və __init__ alt sinifinə zəng __init__ . __init__ sonra bu çağırış konvensiyası gözlənildiyi kimi işləməyə kömək edir.

__init__ hala __new__ superclass tərəfindən tələb olunan hər hansı bir parametrləri həll etmək lazımdır, ancaq aydın runtime səhvini yarada bilməzsiniz. Və __new__ açıq-aydın icazə verməlidir *args və '** kw' genişləndirilməsi yaxşı olduğunu aydınlaşdırmaq üçün.

Bir qayda olaraq, pis forma, həmin sinifdə __new____init__ həm də eyni plakatda təsvir edilmiş davranış kimi eyni miras səviyyəsinə malikdir.

1
18 июня '12 в 19:30 2012-06-18 19:30 Cavab Jay Obermark 18 iyun, saat 12: 30-da 2012-06-18 19:30 tərəfindən verilir

Ancaq __init__ zaman __new__ sonra niyə __init__ bir az qarışdırdım.

Bunun böyük bir səbəbi yoxdur, istisna olmaqla bu şəkildə edilir. __new__ sinifin başlanmasından məsul deyil, başqa bir üsul ( __call__ , bəlkə - mən əminəm).

Bunu gözləmirdim. Hər kəsin bu səbəbdən baş verdiyini və bu funksiyanı necə həyata keçirəcəyimi mənə deyə bilərəmmi? ( __new__ də yerinə yetirilən __new__ başqa, olduqca __new__ görünür).

__init__ artıq __init__ heç bir şey __init__ ola bilər və ya yeni nümunələr üçün yalnız __init__ çağırır və başqa bir halda sadəcə __new__(...) qaytarır ki, yeni __call__ ilə yeni bir metaclass yaza bilərsiniz.

0
23 марта '09 в 20:23 2009-03-23 20:23 Cavab Devin Jeanpierre tərəfindən 23 Mart 'da 20:23' də verildi. 2009-03-23 ​​20:23

Sadə bir səbəb, yeni bir nümunə yaratmaq üçün istifadə edilir və bir örneği başlatmaq üçün init istifadə olunur. Nümunə başlamazdan əvvəl əvvəl yaradılmalıdır. Buna görə yeni bir init proqramından əvvəl çağırılmalıdır.

0
23 марта '18 в 16:48 2018-03-23 16:48 Cavab ZQ Hu tərəfindən verilir 23 Mart '18, 16:48 2018-03-23 ​​16:48

İndi eyni problemim var və nədənsə dekoratör, fabrik və metaclasses qarşısını almaq qərarına gəldim. Bunu belə etdim:

Əsas fayl

 def _alt(func): import functools @functools.wraps(func) def init(self, *p, **k): if hasattr(self, "parent_initialized"): return else: self.parent_initialized = True func(self, *p, **k) return init class Parent: # Empty dictionary, shouldn't ever be filled with anything else parent_cache = {} def __new__(cls, n, *args, **kwargs): # Checks if object with this ID (n) has been created if n in cls.parent_cache: # It was, return it return cls.parent_cache[n] else: # Check if it was modified by this function if not hasattr(cls, "parent_modified"): # Add the attribute cls.parent_modified = True cls.parent_cache = {} # Apply it cls.__init__ = _alt(cls.__init__) # Get the instance obj = super().__new__(cls) # Push it to cache cls.parent_cache[n] = obj # Return it return obj 

Sınıf nümunələri

 class A(Parent): def __init__(self, n): print("A.__init__", n) class B(Parent): def __init__(self, n): print("B.__init__", n) 

Istifadədə

 >>> A(1) A.__init__ 1 # First A(1) initialized <__main__.A object at 0x000001A73A4A2E48> >>> A(1) # Returned previous A(1) <__main__.A object at 0x000001A73A4A2E48> >>> A(2) A.__init__ 2 # First A(2) initialized <__main__.A object at 0x000001A7395D9C88> >>> B(2) B.__init__ 2 # B class doesn't collide with A, thanks to separate cache <__main__.B object at 0x000001A73951B080> 
  • Xəbərdarlıq: valideynin başlanğıcına ehtiyac yoxdur, digər siniflər ilə vuruşacaqsınız - əgər hər bir uşaq üçün ayrı bir önbellek müəyyən etmirsinizsə, bu biz istədiyimiz deyil.
  • Xəbərdarlıq: Bu nənə və baba kimi valideynlə birlikdə sinif görünər, qəribə davranır. [Təsdiqlənməmiş]

İndi cəhd edin!

0
25 июля '18 в 22:21 2018-07-25 22:21 cavab Soaku tərəfindən iyulun 25-də saat 18: 00-da saat 10: 21-də 2018-07-25 22:21

əlaqədar digər suallar, etiketləri və ya sual verin