python中def _init_是什么意思_详细解读Python中的__init__()方法
__init__()方法意義重大的原因有兩個(gè)。第一個(gè)原因是在對(duì)象生命周期中初始化是最重要的一步;每個(gè)對(duì)象必須正確初始化后才能正常工作。第二個(gè)原因是__init__()參數(shù)值可以有多種形式。
因?yàn)橛泻芏喾N方式為_(kāi)_init__()提供參數(shù)值,對(duì)于對(duì)象創(chuàng)建有大量的用例,我們可以看看其中的幾個(gè)。我們想盡可能的弄清楚,因此我們需要定義一個(gè)初始化來(lái)正確的描述問(wèn)題區(qū)域。
在我們接觸__init__()方法之前,無(wú)論如何,我們都需要粗略、簡(jiǎn)單地看看在Python中隱含的object類(lèi)的層次結(jié)構(gòu)。
在這一章,我們看看不同形式的簡(jiǎn)單對(duì)象的初始化(例如:打牌)。在這之后,我們還可以看看更復(fù)雜的對(duì)象,就像包含集合的hands對(duì)象以及包含策略和狀態(tài)的players。
隱含的超類(lèi)——object
每一個(gè)Python類(lèi)都隱含了一個(gè)超類(lèi):object。它是一個(gè)非常簡(jiǎn)單的類(lèi)定義,幾乎不做任何事情。我們可以創(chuàng)建object的實(shí)例,但是我們不能用它做太多,因?yàn)樵S多特殊的方法容易拋出異常。
當(dāng)我們自定義一個(gè)類(lèi),object則為超類(lèi)。下面是一個(gè)類(lèi)定義示例,它使用新的名稱(chēng)簡(jiǎn)單的繼承了object:
1
2
class X:
pass
下面是和自定義類(lèi)的一些交互:
1
2
3
4
>>> X.__class__
>>> X.__class__.__base__
我們可以看到該類(lèi)是type類(lèi)的一個(gè)對(duì)象,且它的基類(lèi)為object。
就像在每個(gè)方法中看到的那樣,我們也看看從object繼承的默認(rèn)行為。在某些情況下,超類(lèi)特殊方法的行為是我們所想要的。在其他情況下,我們需要覆蓋這個(gè)特殊方法。
基類(lèi)對(duì)象的init()方法
對(duì)象生命周期的基礎(chǔ)是創(chuàng)建、初始化和銷(xiāo)毀。我們將創(chuàng)建和銷(xiāo)毀的高級(jí)特殊方法推遲到后面的章節(jié)中,目前只關(guān)注初始化。
所有類(lèi)的超類(lèi)object,有一個(gè)默認(rèn)包含pass的__init__()實(shí)現(xiàn),我們不需要去實(shí)現(xiàn)__init__()。如果不實(shí)現(xiàn)它,則在對(duì)象創(chuàng)建后就不會(huì)創(chuàng)建實(shí)例變量。在某些情況下,這種默認(rèn)行為是可以接受的。
我們總是給對(duì)象添加屬性,該對(duì)象為基類(lèi)object的子類(lèi)。思考以下類(lèi),需要兩個(gè)實(shí)例變量但不初始化它們:
1
2
3
class Rectangle:
def area(self):
return self.length* self.width
Rectangle類(lèi)有一個(gè)使用兩個(gè)屬性來(lái)返回一個(gè)值的方法。這些屬性沒(méi)有初始化。這是合法的Python代碼。它可以有效的避免專(zhuān)門(mén)設(shè)置屬性,雖然感覺(jué)有點(diǎn)奇怪,但是有效。
下面是于Rectangle類(lèi)的交互:
1
2
3
4
>>> r= Rectangle()
>>> r.length, r.width= 13,8
>>> r.area()
104
顯然這是合法的,但也是容易混淆的根源,所以也是我們需要避免的原因。
無(wú)論如何,這個(gè)設(shè)計(jì)給予了很大的靈活性,這樣有時(shí)候我們不用在__init__()方法中設(shè)置所有屬性。至此我們走的很順利。一個(gè)可選屬性其實(shí)就是一個(gè)子類(lèi),只是沒(méi)有真正的正式聲明為子類(lèi)。我們創(chuàng)建多態(tài)在某種程度上可能會(huì)引起混亂以及if語(yǔ)句的不恰當(dāng)使用所造成的盤(pán)繞。雖然未初始化的屬性可能是有用的,但很有可能是糟糕設(shè)計(jì)的前兆。
《Python之禪》中的建議:
"顯式比隱式更好。"
一個(gè)__init__()方法應(yīng)該讓實(shí)例變量顯式。
可憐的多態(tài)
靈活和愚蠢就在一念之間。
當(dāng)我們覺(jué)得需要像下面這樣寫(xiě)的時(shí)候,我們正從靈活的邊緣走向愚蠢:
1
if 'x' in self.__dict__:
或者:
1
2
3
try:
self.x
except AttributeError:
是時(shí)候重新考慮API并添加一個(gè)通用的方法或?qū)傩浴V貥?gòu)比添加if語(yǔ)句更明智。
在超類(lèi)中實(shí)現(xiàn)init()
我們通過(guò)實(shí)現(xiàn)__init__()方法來(lái)初始化對(duì)象。當(dāng)一個(gè)對(duì)象被創(chuàng)建,Python首先創(chuàng)建一個(gè)空對(duì)象,然后為那個(gè)新對(duì)象調(diào)用__init__()方法。這個(gè)方法函數(shù)通常用來(lái)創(chuàng)建對(duì)象的實(shí)例變量并執(zhí)行任何其他一次性處理。
下面是Card類(lèi)示例定義的層次結(jié)構(gòu)。我們將定義Card超類(lèi)和三個(gè)子類(lèi),這三個(gè)子類(lèi)是Card的變種。兩個(gè)實(shí)例變量直接由參數(shù)值設(shè)置,兩個(gè)變量通過(guò)初始化方法計(jì)算:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Card:
def __init__(self, rank, suit):
self.suit= suit
self.rank= rank
self.hard,self.soft= self._points()
class NumberCard(Card):
def _points(self):
return int(self.rank),int(self.rank)
class AceCard(Card):
def _points(self):
return 1,11
class FaceCard(Card):
def _points(self):
return 10,10
在這個(gè)示例中,我們提取__init__()方法到超類(lèi),這樣在Card超類(lèi)中的通用初始化可以適用于三個(gè)子類(lèi)NumberCard、AceCard和FaceCard。
這是一種常見(jiàn)的多態(tài)設(shè)計(jì)。每一個(gè)子類(lèi)都提供一個(gè)唯一的_points()方法實(shí)現(xiàn)。所有子類(lèi)都有相同的簽名:有相同的方法和屬性。這三個(gè)子類(lèi)的對(duì)象在一個(gè)應(yīng)用程序中可以交替使用。
如果我們?yōu)榛ㄉ褂煤?jiǎn)單的字符,我們可以創(chuàng)建Card實(shí)例,如下所示:
1
cards= [AceCard('A','?'), NumberCard('2','?'), NumberCard('3','?'),]
我們?cè)诹斜碇忻杜e出一些牌的類(lèi)、牌值和花色。從長(zhǎng)遠(yuǎn)來(lái)說(shuō),我們需要更智能的工廠(chǎng)函數(shù)來(lái)創(chuàng)建Card實(shí)例;用這個(gè)方法枚舉52張牌無(wú)聊且容易出錯(cuò)。在我們接觸工廠(chǎng)函數(shù)之前,我們看一些其他問(wèn)題。
使用init()創(chuàng)建顯式常量
可以給牌定義花色類(lèi)。在二十一點(diǎn)中,花色無(wú)關(guān)緊要,簡(jiǎn)單的字符串就可以。
我們使用花色構(gòu)造函數(shù)作為創(chuàng)建常量對(duì)象的示例。在許多情況下,我們應(yīng)用中小部分對(duì)象可以通過(guò)常量集合來(lái)定義。小部分的靜態(tài)對(duì)象可能是實(shí)現(xiàn)策略模式或狀態(tài)模式的一部分。
在某些情況下,我們會(huì)有一個(gè)在初始化或配置文件中創(chuàng)建的常量對(duì)象池,或者我們可以基于命令行參數(shù)創(chuàng)建常量對(duì)象。我們會(huì)在第十六章《通過(guò)命令進(jìn)行復(fù)制》中獲取初始化設(shè)計(jì)和啟動(dòng)設(shè)計(jì)的詳細(xì)信息。
Python沒(méi)有簡(jiǎn)單正式的機(jī)制來(lái)定義一個(gè)不可變對(duì)象,我們將在第三章《屬性訪(fǎng)問(wèn)、方法屬性和描述符》看看保證不可變性的相關(guān)技術(shù)。在本示例中,花色不可變是有道理的。
下面這個(gè)類(lèi),我們將用于創(chuàng)建四個(gè)顯式常量:
1
2
3
4
class Suit:
def __init__(self, name, symbol):
self.name= name
self.symbol= symbol
下面是通過(guò)這個(gè)類(lèi)創(chuàng)建的常量:
1
Club, Diamond, Heart, Spade= Suit('Club','?'), Suit('Diamond','?'), Suit('Heart','?'), Suit('Spade','?')
現(xiàn)在我們可以通過(guò)下面展示的代碼片段創(chuàng)建cards:
1
cards= [AceCard('A', Spade), NumberCard('2', Spade), NumberCard('3', Spade),]
這個(gè)小示例,這種方法對(duì)于單個(gè)特性的花色代碼來(lái)說(shuō)并不是一個(gè)巨大的進(jìn)步。在更復(fù)雜的情況下,會(huì)有一些策略或狀態(tài)對(duì)象通過(guò)這個(gè)方式創(chuàng)建。通過(guò)從小的、靜態(tài)的常量對(duì)象中復(fù)用可以使策略或狀態(tài)設(shè)計(jì)模式更有效率。
我們必須承認(rèn),在Python中這些對(duì)象并不是技術(shù)上一成不變的,它是可變的。進(jìn)行額外的編碼使得這些對(duì)象真正不變可能會(huì)有一些好處。
無(wú)關(guān)緊要的不變性
不變性很有吸引力但卻容易帶來(lái)麻煩。有時(shí)候被神話(huà)般的“惡意程序員”在他們的應(yīng)用程序中通過(guò)修改常量值進(jìn)行調(diào)整。從設(shè)計(jì)上考慮,這是非常愚蠢的。這些神話(huà)般的、惡意的程序員不會(huì)停止這樣做,因?yàn)橐呀?jīng)沒(méi)有更好的方法去更簡(jiǎn)潔簡(jiǎn)單的在Python中編碼。惡意程序員訪(fǎng)問(wèn)到源碼并且修改它僅僅是希望盡可能輕松地編寫(xiě)代碼來(lái)修改一個(gè)常數(shù)。
在定義不可變對(duì)象的類(lèi)的時(shí)候最好不要掙扎太久。在第三章《屬性訪(fǎng)問(wèn)、方法屬性和描述符》中,我們將通過(guò)在有bug的程序中提供合適的診斷信息來(lái)展示如何實(shí)現(xiàn)不變性。
總結(jié)
以上是生活随笔為你收集整理的python中def _init_是什么意思_详细解读Python中的__init__()方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 紫银发债是什么
- 下一篇: python机械编程_机器学习编程作业3