Python sınıflarında neden __init__ kullanıyoruz?


124

Sınıfların İlklendirilmesini anlamakta güçlük çekiyorum.

Bunların anlamı nedir ve bunlara neyi dahil edeceğimizi nasıl bileceğiz? Sınıflarda yazmak, işlevler oluşturmaktan farklı bir düşünme türü gerektiriyor mu (Yalnızca işlevler oluşturabileceğimi ve sonra bunları bir sınıfa sararak yeniden kullanabileceğimi düşündüm. Bu işe yarayacak mı?)

İşte bir örnek:

class crawler:
  # Initialize the crawler with the name of database
  def __init__(self,dbname):
    self.con=sqlite.connect(dbname)

  def __del__(self):
    self.con.close()

  def dbcommit(self):
    self.con.commit()

Veya başka bir kod örneği:

class bicluster:
  def __init__(self,vec,left=None,right=None,distance=0.0,id=None):
    self.left=left
    self.right=right
    self.vec=vec
    self.id=id
    self.distance=distance

__init__Başkalarının kodunu okumaya çalışırken karşılaştığım çok fazla sınıf var, ancak onları oluşturmanın mantığını anlamıyorum.


1
init'in hikayesi ... blah, blah, blah .... yapıcı-yıkıcı ama yıkıcı yok çünkü çöp toplama mevcut.
MisterGeeky

Yanıtlar:


289

Yazdıklarınıza göre, kritik bir anlayış parçasını kaçırıyorsunuz: sınıf ve nesne arasındaki fark. __init__bir sınıfı başlatmaz, bir sınıfın veya nesnenin bir örneğini başlatır. Her köpeğin rengi vardır, ancak köpeklerin sınıf olarak yoktur. Her köpeğin dört veya daha az ayağı vardır, ancak köpek sınıfında yoktur. Sınıf, bir nesnenin konseptidir. Fido ve Spot'u gördüğünüzde, benzerliklerini, köpekliklerini anlarsınız. Sınıf bu.

Dediğinde

class Dog:
    def __init__(self, legs, colour):
        self.legs = legs
        self.colour = colour

fido = Dog(4, "brown")
spot = Dog(3, "mostly yellow")

Diyorsun ki, Fido 4 bacaklı kahverengi bir köpek, Spot biraz sakat ve çoğunlukla sarı. __init__İşlevi, bir yapıcısı denir, ya da başlatıcı ve bir sınıfın yeni bir örneğini oluşturduğunuzda otomatik olarak adlandırılır. Bu işlev içinde, yeni oluşturulan nesne parametreye atanır self. Gösterim self.legs, legsdeğişkendeki nesnenin adı verilen bir özniteliktir self. Öznitelikler bir çeşit değişken gibidir, ancak bir nesnenin durumunu veya nesnenin kullanabileceği belirli eylemleri (işlevleri) tanımlar.

Ancak, colourköpekliğin kendisi için belirlemediğinizi unutmayın - bu soyut bir kavramdır. Sınıflar üzerinde anlamlı olan nitelikler vardır. Örneğin, population_sizeböyle bir şey - Fido'yu saymak mantıklı değil çünkü Fido her zaman birdir. Köpekleri saymak mantıklı. Diyelim ki dünyada 200 milyon köpek var. Bu, Dog sınıfının malıdır. Fido'nun 200 milyon sayısıyla ilgisi yok, Spot da yok. Bu colourveya legsüstü "örnek özniteliklerinin" aksine "sınıf özniteliği" olarak adlandırılır .

Şimdi, daha az köpek ve daha programlama ile ilgili bir şeye. Aşağıda yazdığım gibi, bir şeyler eklemek için sınıf mantıklı değil - bu sınıf nedir? Python'daki sınıflar, benzer şekilde davranan farklı veri koleksiyonlarından oluşur. Köpekler sınıfı, Fido ve Spot ve bunlara benzer 199999999998 diğer hayvanlardan oluşur ve hepsi de elektrik direklerine işer. Bir şeyler eklemek için sınıf nelerden oluşur? İçlerinde bulunan hangi verilere göre farklılık gösterirler? Ve hangi eylemleri paylaşıyorlar?

Ancak sayılar ... bunlar daha ilginç konular. Tamsayılar diyelim. Köpeklerden çok daha fazlası var. Python'un zaten tam sayılara sahip olduğunu biliyorum, ama hadi aptalı oynayalım ve onları tekrar "uygulayalım" (hile yaparak ve Python'un tam sayılarını kullanarak).

Yani, Tamsayılar bir sınıftır. Bazı verileri (değeri) ve bazı davranışları ("beni bu sayıya ekle") vardır. Şunu gösterelim:

class MyInteger:
    def __init__(self, newvalue)
        # imagine self as an index card.
        # under the heading of "value", we will write
        # the contents of the variable newvalue.
        self.value = newvalue
    def add(self, other):
        # when an integer wants to add itself to another integer,
        # we'll take their values and add them together,
        # then make a new integer with the result value.
        return MyInteger(self.value + other.value)

three = MyInteger(3)
# three now contains an object of class MyInteger
# three.value is now 3
five = MyInteger(5)
# five now contains an object of class MyInteger
# five.value is now 5
eight = three.add(five)
# here, we invoked the three's behaviour of adding another integer
# now, eight.value is three.value + five.value = 3 + 5 = 8
print eight.value
# ==> 8

Bu biraz kırılgan ( otherbir MyInteger olacağını varsayıyoruz), ancak şimdi görmezden geleceğiz. Gerçek kodda yapmayız; emin olmak için test ederdik ve hatta belki de zorlarız ("sen bir tamsayı değil misin? Aman tanrım, bir olmak için 10 nanosaniye var! 9 ... 8 ....")

Kesirleri bile tanımlayabiliriz. Kesirler ayrıca kendilerini nasıl toplayacaklarını da bilirler.

class MyFraction:
    def __init__(self, newnumerator, newdenominator)
        self.numerator = newnumerator
        self.denominator = newdenominator
        # because every fraction is described by these two things
    def add(self, other):
        newdenominator = self.denominator * other.denominator
        newnumerator = self.numerator * other.denominator + self.denominator * other.numerator
        return MyFraction(newnumerator, newdenominator)

Tamsayılardan bile daha fazla kesir vardır (gerçekten değil, ancak bilgisayarlar bunu bilmiyor). İki yapalım:

half = MyFraction(1, 2)
third = MyFraction(1, 3)
five_sixths = half.add(third)
print five_sixths.numerator
# ==> 5
print five_sixths.denominator
# ==> 6

Aslında burada hiçbir şey beyan etmiyorsunuz. Nitelikler yeni bir değişken türü gibidir. Normal değişkenlerin yalnızca bir değeri vardır. Yazın diyelim colour = "grey". Sen adında başka değişkeni olamaz colourolduğu "fuchsia"değil kodda aynı yerde -.

Diziler bunu bir dereceye kadar çözer. Derseniz colour = ["grey", "fuchsia"], değişkene içine iki renk yığılmış var, ancak (bu durumda, 0 veya 1) konumlarına göre ayırt.

Nitelikler, bir nesneye bağlı değişkenlerdir. Dizilerde olduğu gibi , farklı köpeklerde birçok colourdeğişkenimiz olabilir . Öyleyse, bir değişken, ama başka. İlki, değişken içindeki nesneye bağlıdır ; ikinci ,. Şimdi, veya aradığınızda , her zaman görünmez bir parametre olacak ve bu parametre listesinin önündeki sarkan fazladan bir parametreye atanacaktır. Geleneksel olarak adlandırılır ve noktanın önündeki nesnenin değerini alır. Böylece, Köpeğin (kurucu) içinde, yeni Köpeğin ortaya çıkacağı şey olacaktır; içinde 's , değişkendeki nesneye bağlanacaktır . Böylece,fido.colourspot.colourfidospotDog(4, "brown")three.add(five)self__init__selfMyIntegeraddselfthreethree.valuedışında aynı değişken olacak addşekilde, self.valueiçinde add.

Söylersem the_mangy_one = fido, ben olarak bilinen nesneye atıfta başlayacak fidobir başka isimle. Şu andan itibaren fido.colour, tamamen aynı değişkendir the_mangy_one.colour.

Yani, içindeki şeyler __init__. Bunları, Köpeğin doğum belgesine bir şeyler yazıyormuş gibi düşünebilirsiniz. colourkendi başına rastgele bir değişkendir, herhangi bir şey içerebilir. fido.colourveya self.colourKöpeğin kimlik sayfasındaki bir form alanı gibidir; ve __init__katip ilk kez dolduruyor.

Daha net mi?

DÜZENLEME : Aşağıdaki yorumun genişletilmesi:

Nesnelerin bir listesini kastediyorsun , değil mi?

Her şeyden önce, fidoaslında bir nesne değil. Şu anda bir nesneyi içeren bir değişkendir, tıpkı sizin dediğinizde olduğu gibi x = 5, xşu anda beş sayısını içeren bir değişkendir. Daha sonra fikrinizi değiştirirseniz, bunu yapabilirsiniz fido = Cat(4, "pleasing")(bir sınıf oluşturduğunuz sürece Cat) ve fidoo andan itibaren bir kedi nesnesi "içerebilirsiniz". Bunu yaparsanız fido = x, o zaman beş numara içerecek ve hiçbir hayvan nesnesi olmayacak.

Bir sınıf, siz onları takip etmek için özel olarak kod yazmadığınız sürece örneklerini kendi başına bilmez. Örneğin:

class Cat:
    census = [] #define census array

    def __init__(self, legs, colour):
        self.colour = colour
        self.legs = legs
        Cat.census.append(self)

Burada, censussınıfın sınıf düzeyinde bir özelliği var Cat.

fluffy = Cat(4, "white")
spark = Cat(4, "fiery")
Cat.census
# ==> [<__main__.Cat instance at 0x108982cb0>, <__main__.Cat instance at 0x108982e18>]
# or something like that

Almayacağınızı unutmayın [fluffy, sparky]. Bunlar sadece değişken isimlerdir. Kedilerin kendi adlarının olmasını istiyorsanız, ad için ayrı bir öznitelik oluşturmanız ve ardından __str__bu adı döndürmek için yöntemi geçersiz kılmanız gerekir . Bu yöntemin (yani sınıfa bağlı işlevi, tıpkı addveya gibi __init__) amacı, nesneyi yazdırırken olduğu gibi bir dizeye nasıl dönüştürebileceğini açıklamaktır.


7
vay, teşekkürler..bu aslında bana çok mantıklı geldi, bu yüzden ne olduğunu yapan herhangi bir şey, init işlevinde önceden bildirmem gerekiyor. Bu durumda Köpek'in bacakları ve rengi vardır. Örneğin, iki sayı ekleyen bir sınıf yapsaydım, self.firstnumber ve self.secondnumber olarak tanımlardım, o zaman cevabı almak için sınıfta sadece firstnumber + secondnumber?
Lostsoul

1
Türü. Bunu yapabilirsin. Ancak bir şeyler eklemek için bir sınıf yapmak pek mantıklı değil. Sınıflar normalde verileri davranışlarla uygular - saf davranışlar yalnızca işlevlerdir. Cevabı alakalı bir şeyle genişleteceğim; biraz bekle.
Amadan

3
Harika cevap için teşekkür ederim. Artık sınıfların gücünü görüyorum ve anlıyorum. Aptalca geliyorsa özür dilerim. Sadece ben, verileri sıralayabileceğimi ve aynı anda birçok farklı şeyin durumunu koruyabileceğimi fark ettim (oysa ben yalnızca oluşturabildiğim kadar çok değişkeni veya döngüler yoluyla daha fazlasını izlerdim). Diyelim ki, köpek başına ortalama bacak sayısını bulmam gerekiyor? Bir sınıfla oluşturduğum tüm nesnelerin bir listesini almanın bir yolu var mı, böylece böyle bir eğitim başlatabilir miyim? yoksa oluşturduğum sınıfların bir listesini de
tutmalı mıyım

23

5 sentimi Amadan'dan kapsamlı açıklamaya katkıda bulunmak için .

Sınıflar, soyut bir şekilde "bir türün" tanımıdır. Nesneler onların kavrayışlarıdır: yaşayan nefes alan şey. Nesne yönelimli dünyada, neredeyse her şeyin özü diyebileceğiniz temel fikirler vardır. Onlar:

  1. kapsülleme (bu konuda ayrıntılı bilgi vermeyeceğiz)
  2. miras
  3. polimorfizmi

Nesnelerin bir veya daha fazla özelliği (= Nitelikler) ve davranışları (= Yöntemler) vardır. Davranış çoğunlukla özelliklere bağlıdır. Sınıflar, davranışın genel olarak neyi başarması gerektiğini tanımlar, ancak sınıf bir nesne olarak gerçekleştirilmediği (somutlaştırılmadığı) sürece, soyut bir olasılık kavramı olarak kalır. "Kalıtım" ve "polimorfizm" yardımıyla açıklayayım.

    class Human:
        gender
        nationality
        favorite_drink
        core_characteristic
        favorite_beverage
        name
        age

        def love    
        def drink
        def laugh
        def do_your_special_thing                

    class Americans(Humans)
        def drink(beverage):
            if beverage != favorite_drink: print "You call that a drink?"
            else: print "Great!" 

    class French(Humans)
        def drink(beverage, cheese):
            if beverage == favourite_drink and cheese == None: print "No cheese?" 
            elif beverage != favourite_drink and cheese == None: print "Révolution!"

    class Brazilian(Humans)
        def do_your_special_thing
            win_every_football_world_cup()

    class Germans(Humans)
        def drink(beverage):
            if favorite_drink != beverage: print "I need more beer"
            else: print "Lecker!" 

    class HighSchoolStudent(Americans):
        def __init__(self, name, age):
             self.name = name
             self.age = age

jeff = HighSchoolStudent(name, age):
hans = Germans()
ronaldo = Brazilian()
amelie = French()

for friends in [jeff, hans, ronaldo]:
    friends.laugh()
    friends.drink("cola")
    friends.do_your_special_thing()

print amelie.love(jeff)
>>> True
print ronaldo.love(hans)
>>> False

Bazı özellikler insanı tanımlar. Ancak her millet biraz farklıdır. Yani "ulusal tipler" ekstraları olan bir nevi İnsanlardır. "Amerikalılar" bir tür "İnsanlar" dır ve insan türünden (temel sınıf) bazı soyut özellikler ve davranışlar miras alırlar: bu kalıtımdır. Böylece tüm İnsanlar gülebilir ve içebilir, bu nedenle tüm çocuk sınıfları da yapabilir! Kalıtım (2).

Ama hepsi aynı türden olduğu için (Tip / temel-sınıf: İnsanlar) onları bazen değiş tokuş edebilirsiniz: sondaki for-döngüsüne bakın. Ancak bireysel bir özelliği açığa çıkaracaklar ve bu Polimorfizmdir (3).

Yani her insanın bir favori içeceği vardır, ancak her millet özel bir içkiye yönelir. Bir uyruğu İnsan türünden alt sınıflarsanız, yukarıda drink()Yöntem ile gösterdiğim gibi kalıtsal davranışın üzerine yazabilirsiniz . Ama bu hala sınıf düzeyinde ve bu nedenle hala bir genelleme.

hans = German(favorite_drink = "Cola")

Almanca sınıfını somutlaştırır ve başlangıçta varsayılan bir özelliği "değiştirdim". (Ama hans.drink ('Süt') olarak adlandırırsanız, yine de "Daha fazla biraya ihtiyacım var" yazardı - bariz bir hata ... ya da belki de daha büyük bir Şirketin Çalışanı olsaydım bir özellik olarak adlandıracağım şey budur. ;-)! )

Bir türün karakteristiği, örneğin Almanlar (hanlar) genellikle somutlama __init__anında kurucu aracılığıyla (python'da:) tanımlanır . Nesne olacak bir sınıfı tanımladığınız nokta budur. Hayatı, bireysel özelliklerle doldurarak ve bir nesne haline getirerek soyut bir kavram (sınıf) haline getirin diyebilirsiniz.

Ancak her nesne bir sınıfın bir örneği olduğu için bazı temel karakteristik türleri ve bazı davranışları paylaşırlar. Bu, nesne yönelimli konseptin önemli bir avantajıdır.

Her bir nesnenin özelliklerini korumak için, onları içine alırsınız - davranış ile karakteristiği birleştirmeye çalıştığınız ve onu nesnenin dışından değiştirmeyi zorlaştırdığınız anlamına gelir. Bu Kapsülleme (1)


5

Sadece örneğin değişkenlerini başlatmak içindir.

Örneğin crawler, belirli bir veritabanı adına sahip bir örnek oluşturun (yukarıdaki örneğinizden).


Üzgünüm, bunun ne anlama geldiğini gerçekten anlamıyorum .. Yukarıdaki örnekte .. geliştirici ana koduna 'left = foo', vb.
Eklemiş olamazdı

Fonksiyonun varsayılan değerlerini mi kastediyorsunuz? left=NoneLeft, Noneoluşturulduktan sonra leftparametre belirtilmezse olarak başlatılacaktır .
jldupont

Sanırım mantıklı gelmeye başladı ... Değişkenlerinizi java'da önceden "String left" veya başka bir şekilde önceden beyan etmeniz gerektiği gibi mi? sonra sınıfa ilklendirildiğinde, değerleri değiştirebilir misiniz? Fonksiyonlarla karşılaştırıldığında biraz kafa karıştırıcı çünkü fonksiyonlara sadece değerler gönderebiliyorum ve önceden hiçbir şeyi başlatmam gerekmiyor.
Lostsoul

1
@Lostsoul: left = fooişe yarardı - bir kez. Sınıfların amacı, her farklı için mantıklı bir şeyler yapmaktır crawler. Sınıflar işlevler veya işlevlerle karşılaştırılabilecek bir şey değildir (pekala, çok daha gelişmiş olana ve işlevsel programlamaya girene kadar değil, ama bu şimdi kafanızı karıştıracaktır). Derslerin gerçekte ne olduğuna dair cevabımı oku - hala anlamıyorsun.
Amadan

4

__init__Örneklerinizin değiştirilebilir niteliklerini doğru şekilde başlatmak istiyorsanız Python'da kullanmanız gerekiyor gibi görünüyor .

Aşağıdaki örneğe bakın:

>>> class EvilTest(object):
...     attr = []
... 
>>> evil_test1 = EvilTest()
>>> evil_test2 = EvilTest()
>>> evil_test1.attr.append('strange')
>>> 
>>> print "This is evil:", evil_test1.attr, evil_test2.attr
This is evil: ['strange'] ['strange']
>>> 
>>> 
>>> class GoodTest(object):
...     def __init__(self):
...         self.attr = []
... 
>>> good_test1 = GoodTest()
>>> good_test2 = GoodTest()
>>> good_test1.attr.append('strange')
>>> 
>>> print "This is good:", good_test1.attr, good_test2.attr
This is good: ['strange'] []

Bu, her özniteliğin otomatik olarak yeni bir değerle başlatıldığı Java'da oldukça farklıdır:

import java.util.ArrayList;
import java.lang.String;

class SimpleTest
{
    public ArrayList<String> attr = new ArrayList<String>();
}

class Main
{
    public static void main(String [] args)
    {
        SimpleTest t1 = new SimpleTest();
        SimpleTest t2 = new SimpleTest();

        t1.attr.add("strange");

        System.out.println(t1.attr + " " + t2.attr);
    }
}

sezgisel olarak beklediğimiz bir çıktı üretir:

[strange] []

Ama attrolarak ilan ederseniz static, Python gibi davranacaktır:

[strange] [strange]

3

Senin ile takip araba Örneğin: Bir araba alınca, sadece rastgele bir araba almıyorsun, Yani, vb renk, marka, koltuk sayısını, seçim Ve bazı şeyler size seçmeden "initialize" da bunun için, tekerlek sayısı veya kayıt numarası gibi.

class Car:
    def __init__(self, color, brand, number_of_seats):
        self.color = color
        self.brand = brand
        self.number_of_seats = number_of_seats
        self.number_of_wheels = 4
        self.registration_number = GenerateRegistrationNumber()

Dolayısıyla, __init__yöntemde oluşturduğunuz örneğin özniteliklerini tanımlıyorsunuz. Öyleyse, mavi bir Renault arabası istiyorsak, 2 kişi için, aşağıdaki Cargibi bir örneği başlatırız :

my_car = Car('blue', 'Renault', 2)

Bu şekilde, Carsınıfın bir örneğini oluşturuyoruz . __init__(Gibi bizim belirli özellikler işleyen biridir colorya da brand) ve bunun gibi diğer özellikleri üretilmesi registration_number.


3

Sınıflar, o nesneye özgü niteliklere (durum, karakteristik) ve yöntemlere (işlevler, kapasiteler) sahip nesnelerdir (bir ördek için sırasıyla beyaz renk ve uçma güçleri gibi).

Bir sınıfın bir örneğini yarattığınızda, ona bir miktar başlangıç ​​kişiliği verebilirsiniz (adı ve yeni doğmuş bir bebek için elbisesinin rengi gibi durum veya karakter). Bunu ile yaparsınız __init__.

Temel __init__olarak, aradığınızda örnek özelliklerini otomatik olarak ayarlar instance = MyClass(some_individual_traits).


2

__init__Fonksiyon sınıfında tüm üye değişkenleri oluşturmaktadır. Böylece, bir kez çift kümeniz oluşturulduktan sonra üyeye erişebilir ve bir değer geri alabilirsiniz:

mycluster = bicluster(...actual values go here...)
mycluster.left # returns the value passed in as 'left'

Check out Python Dokümanlar bazı bilgi için. Öğrenmeye devam etmek için OO kavramları üzerine bir kitap almak isteyeceksiniz.


1
class Dog(object):

    # Class Object Attribute
    species = 'mammal'

    def __init__(self,breed,name):
        self.breed = breed
        self.name = name

Yukarıdaki örnekte, her zaman aynı olacağı için türleri küresel olarak kullanıyoruz (bir tür sabit diyebilirsiniz). __init__yöntemi çağırdığınızda içindeki tüm değişken __init__başlatılacaktır (örneğin: cins, isim).

class Dog(object):
    a = '12'

    def __init__(self,breed,name,a):
        self.breed = breed
        self.name = name
        self.a= a

Yukarıdaki örneği aşağıdaki gibi arayarak yazdırırsanız

Dog.a
12

Dog('Lab','Sam','10')
Dog.a
10

Bu, yalnızca nesne oluşturma sırasında başlatılacağı anlamına gelir. bu nedenle, sabit olarak ilan etmek istediğiniz herhangi bir şey onu küresel yapar ve değişen herhangi bir şey kullanır __init__

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.