2013-08-19 104 views
2

抱歉發佈這樣一個奇怪的問題,通常當我感到困惑時,我只是「隨它而行」,直到我有了頓悟,然後將其整理出來,但在我的課程中調用def __init__(self):似乎完全是多餘的,似乎只是讓它工作而已還有:使用類創建對象,爲什麼我需要__init __(self,args):?

class Pet(object): 
    type_of_pet = "" 
    number_of_legs = 0 
    name = "" 

讓我創建:

fred = pet() 
fred.type_of_pet = "alligator" 

還是一樣,好像我是在類更改爲:

class Pet(object): 
    def __init__(self): 
     type_of_pet = "" 

alice = Pet() 
alice.type_of_pet = "Pterodactyl" 

我只是沒有得到爲什麼我需要__init__和其他線程在這裏沒有我希望的那麼清晰。有什麼我可以做這個「點擊」?

+0

您_definitely_不想在'__init__'中寫入'type_of_pet =「」'。這只是設置一個立即消失的局部變量。你可能想要'self.type_of_pet =「」'。但更好的是,您可能希望將'type_of_pet'作爲參數,並將該值複製到該屬性。 – abarnert

+0

另外,真的沒有理由在這個類上擁有這三個類的屬性。這不是Java或C++,您需要先聲明變量和成員,然後才能使用它們。事實上,你正在做的是在類上創建成員,由所有實例共享,然後通過在具有相同名稱的實例上創建成員來隱藏它們。 – abarnert

回答

6

將賦值語句放在類定義中不會聲明實例屬性;它設置了類的屬性。如果你這樣做,所有的寵物將共享相同的name,type_of_petnumber_of_legs

__init__是,除其他事項外,用於設置實例的屬性:

def __init__(self, type_of_pet, name, number_of_legs): 
    self.type_of_pet = type_of_pet 
    self.name = name 
    self.number_of_legs = number_of_legs 

這將在實例上設置屬性,而不是類,所以每個對象將有自己的名稱,類型和腿計數。

+0

好吧,我注意到把東西放在類下面就像是一個全局變量......初始化只是讓我每次做newThing = Class()我都指派「本地」屬性而不是「全局變量」? – ford

+0

@福爾德:全局/本地和類/實例是非常相似的概念,並且將一些東西放在'__init__'和類級別之間非常類似於使其成爲本地而不是全局。請注意,屬性綁定到對象而不是'__init__'方法,因此對對象的任何方法調用都將看到相同的屬性,而不是創建新的屬性。這與函數中的局部變量不同。 – user2357112

+0

太棒了。這真的很有幫助。非常感謝。 – ford

0

當您直接在類中定義成員時,這些成員將成爲類本身的一部分,而不是類的實例的一部分。您仍然可以通過實例訪問它們,但每個實例都沒有自己的實例。

1

__init__ is a kind of constructor, when a instance of a class is created, python calls __init__() during the instantiation to define additional behavior that should occur when a class is instantiated, basically setting up some beginning values for that object or running a routine required on instantiation.

source)

例如,你可以改變你的寵物類:

class Pet(object): 
    def __init__(self, type_of_pet): 
     self.type_of_pet = type_of_pet 

,並作出新的實例有:

alice = Pet("Pterodactyl") 

如果初始化類變量在__init__函數之外,每個實例將共享th在價值。這對靜態類很有用,但我不認爲你想在「普通」類上使用這種行爲。

順便說一句,你不能使用type_of_pet=""__init__,它必須是self.type_of_pet=""

2

__init__在創建類後立即在您的類的每個實例上調用。這是進行實例級初始化的正確位置。

您的type_of_pet和您的第一個示例中定義的其他屬性是類級別的信息。該表格聲明Pet類本身具有type_of_pet值,並且該值存在於與您可能定義的任何方法相同的級別。

當你爲一個名字檢查一個實例時,它將得到分配給該實例的值(如果有的話),或者如果沒有的話,則轉到類的級別。所以這個:

fred = Pet() 
print fred.type_of_pet 

實際檢查類本身type_of_pet

分配將只修改對象,你實際調用它,所以這在實例級別設置一個值:

fred.type_of_pet = 'alligator' 

這使得不改變類,只是把一個值的名稱type_of_petfred實例。因此,使用類級定義作爲實例的默認值很常見。

但是,這會給你帶來麻煩的是像列表這樣的可變類型。這不會做你所期望的:

class Pet: 
    vaccinations = [] 

fido = Pet() 
fido.vaccinations.append('rabies') 

因爲fido.vaccinations結束是在類級別定義的單一列表的引用。相反,你會使用__init__給每個寵物自己的獨立名單。個人而言,我越來越認爲使用類級屬性作爲默認類型的不變性類型會造成更多的混亂而不是它的價值,應該只保存用於真正應該在類級而不是每級跟蹤的事物實例。但那是意見。

1

你問爲什麼你需要__init__()當你可以在類實例化後分配屬性。

答案是,所以你可以在實例化對象時傳遞屬性值,就像你應該的那樣。這不僅可以節省你打字的時間,實例化後,在類上分配屬性容易出錯:如果不小心將其分配爲number_off_legs而不是number_of_legs?這本身並不是一個錯誤,因爲屬性可以被命名爲任何東西,但是會導致其他代碼(預計number_of_legs)失敗,或者在您的情況下會導致錯誤的數據(因爲此類上的默認值將用於此處點)。此外,如果您需要更改屬性名稱,則該名稱爲全部爲您的代碼,因此您需要在很多地方更改它。

因此,爲了避免這些問題,您需要編寫一個小函數來創建對象,然後在其上分配屬性,並在給出對象之前執行任何其他必要的初始化(打開文件,創建從屬對象等)反對你。這是您的__init__()方法,Python有助於將它附加到您的類,以便您可以實例化對象並一次傳入所有屬性值。當你只是存儲一些數據時,它看起來並不是很有用,但是當你的類變得更復雜時,你會發現它非常方便。

相關問題