Python yapıcıları ve __init__


107

Neden kuruculara gerçekten "Oluşturucular" deniyor? Amaçları nedir ve bir sınıftaki yöntemlerden nasıl farklıdırlar?

Ayrıca, __init__bir sınıfta birden fazla olabilir mi? Aşağıdakileri denedim, birisi sonucu açıklayabilir mi?

>>> class test:
    def __init__(self):
        print "init 1"
    def __init__(self):
        print "init 2"

>>> s=test()
init 2

Son olarak, __init__bir operatör aşırı yükleyici mi?


41
Teknik olarak, __init__bir başlatıcıdır . Piton yapıcısı olduğunu __new__. Python, otomatik iki aşamalı başlatmayı kullanır - __new__geçerli ancak (genellikle) doldurulmamış bir nesne döndürür ( boolbir karşı örnek için bakın ), bu daha sonra __init__otomatik olarak çağırır. Bu, C ++ gibi dillerin kısmen oluşturulmuş nesnelerde yaşadığı sorunları ortadan kaldırır - Python'da hiçbir zaman sahip olmazsınız (kısmen başlatılmış olsa da). Neredeyse her ikisi geçersiz kılmak gerekir asla __new__ve __init__bir sınıf üzerinde.
Tim Delaney

2
@TimDelaney: C ++ 'da kısmen oluşturulmuş nesnelerle ne demek istediğinizden emin değilim.
Sebastian Mach

11
@phresnel C ++ 'da nesnenin türü, temel sınıf kurucusundayken temel sınıftır (alt sınıf değil). Temel sınıf yapıcısında sanal bir yöntemi çağıramazsınız ve alt sınıfın uygulamayı sağlamasını sağlayamazsınız. Java'da, temel sınıf yapıcısında bir alt sınıf yöntemini çağırabilirsiniz, ancak alt sınıf üyesi değişkenleri , temel sınıf oluşturucusundan (ve yöntem çağrısından) sonra otomatik olarak başlatılacaktır . Python gibi iki aşamalı başlatmaya sahip dillerde, temel sınıf başlatıcıdaki yöntemleri mutlu bir şekilde çağırabilir ve alt sınıfın davranışı sağlamasını (veya geçersiz kılmasını) sağlayabilirsiniz.
Tim Delaney

@TimDelaney: Ah, açıkladığınız için teşekkürler.
Sebastian Mach

4
@Kafadergisi. Yorumunuzun kabul edilen cevabın yerini alması gerektiğini düşünüyorum.
flamenko

Yanıtlar:


114

Python'da işlev aşırı yüklemesi yoktur, bu da aynı ada ancak farklı argümanlara sahip birden fazla işleve sahip olamayacağınız anlamına gelir.

Kod örneğinizde aşırı yükleme yapmıyorsunuz __init__(). Olan şey, ikinci tanımın adı yeni yönteme yeniden bağlayarak__init__ ilk yöntemi erişilemez hale getirmesidir.

İnşaatçılar hakkındaki genel sorunuza gelince, Wikipedia iyi bir başlangıç ​​noktasıdır. Python'a özgü şeyler için Python belgelerini şiddetle tavsiye ederim .


Aynı zamanda kaynak dosyanın sırayla ayrıştırıldığı (yorumlandığı) anlamına mı geliyor? Daha sonra tanımladığım işlevin daha önce aynı isimle tanımladığım işlevin üzerine yazdığından emin olabilir miyim? :(
Q'm

4
@ 0xc0de: Python'da, işlev tanımları aslında çalıştırılabilir ifadelerdir ve yukarıdan aşağıya doğru çalıştırılırlar, yani evet.
NPE

1
@ 0xc0de Gerçekte olan şey, sınıfın gövdesinin kendi ad alanında yürütülmesidir, bu ad alanı daha sonra meta sınıfa aktarılır (ad ve tabanlar arasında). Fonksiyon tanımları daha sonra sadece belirtilen gövdeyle bir fonksiyon yaratır ve ismine atar. Son ödev __init__, sınıfta biten şey olacaktır.
07'de skyking

64

Neden kuruculara gerçekten "Oluşturucular" deniyor?

Yapıcı (adlandırılmış __new__), sınıfın yeni bir örneğini oluşturur ve döndürür. Dolayısıyla, C.__new__sınıf yöntemi, C sınıfının yapıcısıdır .

C.__init__Oluşturulduktan sonra örnek yöntemi arayana geri geçirilen önce başlatılması, belirli bir örneğinde denir. Bu yöntem, yeni C örnekleri için başlatıcıdır .

Bir sınıftaki yöntemlerden nasıl farklıdırlar?

Belirtildiği gibi resmi belgeler __init__ olduğu örneği oluşturulduktan sonra denir . Diğer yöntemler bu tedaviyi almaz.

Amaçları ne?

Yapıcının amacı, C.__new__yeni bir Cörneğin oluşturulması sırasında özel davranışı tanımlamaktır .

Başlatıcı'nın amacı , oluşturulduktan sonra C.__init__her bir vakanın özel başlatılmasını tanımlamaktır C.

Örneğin Python şunları yapmanıza izin verir:

class Test(object):
    pass

t = Test()

t.x = 10   # here you're building your object t
print t.x

Ama her şeyi istiyorsan örneğiniTestx 10'a eşit bir özniteliğe sahip olmasını istiyorsanız, bu kodu içine koyabilirsiniz __init__:

class Test(object):
    def __init__(self):
        self.x = 10

t = Test()
print t.x

Her örnek yöntem (bir sınıfın belirli bir örneğinde çağrılan bir yöntem), örneği ilk argümanı olarak alır. Bu argüman geleneksel olarak adlandırılmıştır self.

Yapıcı gibi sınıf yöntemleri, __new__bunun yerine sınıfı ilk bağımsız değişkeni olarak alır.

Şimdi, için özel değerler istiyorsanız x öznitelik tek yapmanız gereken bu değeri bağımsız değişken olarak iletmektir.__init__ :

class Test(object):
    def __init__(self, x):
        self.x = x

t = Test(10)
print t.x
z = Test(20)
print t.x

Umarım bu, bazı şüphelerinizi gidermenize yardımcı olur ve diğer sorulara zaten iyi yanıtlar aldığınız için burada duracağım :)


9

Sınıflar, basitçe nesnelerin yaratılacağı planlardır. Yapıcı, her nesne oluşturduğunuzda çalıştırılan bir koddur. Bu nedenle iki kurucuya sahip olmak mantıklı değil. Olan şey, ikincisinin birinciyi fazla yazmasıdır.

Bunları tipik olarak kullandığınız şey, bu nesne için aşağıdaki gibi değişkenler oluşturmaktır:

>>> class testing:
...     def __init__(self, init_value):
...         self.some_value = init_value

Öyleyse yapabileceğiniz şey, bu sınıftan şuna benzer bir nesne oluşturmaktır:

>>> testobject = testing(5)

Testobject some_valuebu örnekte 5 olacak şekilde adlandırılan bir nesneye sahip olacaktır.

>>> testobject.some_value
5

Ancak, örneğimde yaptığım gibi her nesne için bir değer belirlemenize gerek yoktur. Ayrıca şunu da yapabilirsiniz:

>>> class testing:
...     def __init__(self):
...         self.some_value = 5

o zaman some_value'nun değeri 5 olur ve nesneyi oluşturduğunuzda onu ayarlamanız gerekmez.

>>> testobject = testing()
>>> testobject.some_value
5

Örneğimdeki >>> ve ... yazdığınız şey değil. Pyshell'de nasıl görüneceği ...


Sorun değil, yardımcı olduğu için sevindim :)
Niclas Nilsson

1

Yeni bir nesne oluşturduğunuzda, böylece nesneyi "oluşturduğunuzda" ortak oluşturucular otomatik olarak çağrılır. Birden fazla inite sahip olabilmenizin nedeni , isimlerin sadece python'da referans olması ve istediğiniz zaman her bir değişkenin referansını değiştirmenize izin verilmesidir (dolayısıyla dinamik yazım)

def func(): #now func refers to an empty funcion
    pass
...
func=5      #now func refers to the number 5
def func():
    print "something"    #now func refers to a different function

sınıf tanımınızda, sadece sonrakini tutar


0

Python'da yöntem aşırı yükleme kavramı yoktur. Ancak, isteğe bağlı ve anahtar kelime argümanları belirleyerek benzer bir etki elde edebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.