什么是對(duì)象
Python中所有的數(shù)據(jù)都是以對(duì)象的形式存在,無(wú)論是簡(jiǎn)單的數(shù)字類型還是復(fù)雜的代碼模塊此疹。在Python中瞳别,當(dāng)我們想要?jiǎng)?chuàng)建屬于自己的對(duì)象或者修改已有對(duì)象的行為時(shí)麦牺,才需要關(guān)注對(duì)象的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。
對(duì)象既包含數(shù)據(jù)(變量酪我,更習(xí)慣稱之為特性,attribute),也包含代碼(函數(shù)遂庄,也稱為方法)。它是某一類具體事物的特殊實(shí)例劲赠。涛目。例如秸谢,整數(shù) 7 就是一個(gè)包含了加法、乘法之類方法的對(duì) 象霹肝,這些方法在 2.2 節(jié)曾經(jīng)介紹過(guò)估蹄。整數(shù) 8 則是另一個(gè)對(duì)象。這意味著在 Python 里阿迈,7 和 8都屬于一個(gè)公共的類元媚,我們稱之為整數(shù)類。
當(dāng)要?jiǎng)?chuàng)建一個(gè)沒(méi)有創(chuàng)建過(guò)的新對(duì)象時(shí)苗沧,必須首先定義一個(gè)類刊棕,用以指明該類型的對(duì)象包含的內(nèi)容(特性和方法)。
可以把對(duì)象想象成名詞待逞,那么方法就是動(dòng)詞甥角。對(duì)象代表這一個(gè)獨(dú)立的事物,它的方法則定義了它時(shí)如何與其他事物相互作用的识樱。
與模塊不同嗤无,我們可以同時(shí)創(chuàng)建很多同類的對(duì)象,它們的特性值可能各不相同怜庸。對(duì)象就像是包含了代碼的超級(jí)數(shù)據(jù)結(jié)構(gòu)当犯。
實(shí)用class定義類
類(class)就是制作對(duì)象的模具。例如割疾,Python 的內(nèi)置類 String 可以創(chuàng)建像 'cat' 和 'duck' 這樣的字符串對(duì)象嚎卫。在python中想要?jiǎng)?chuàng)建對(duì)象,要首先通過(guò)class關(guān)鍵字創(chuàng)建一個(gè)類宏榕。
class Person():
def __init__(self,name):
self.name = name
hunter = Person('Elmer Fudd')
name參數(shù)作為對(duì)象的特性存儲(chǔ)在了對(duì)象里拓诸,可以直接進(jìn)行讀寫(xiě)
print('The nighty hunter:',hunter.name)
The nighty hunter: Elmer Fudd
其中的__init__()
是python中特殊的對(duì)象初始化方法,用于根據(jù)類的定義創(chuàng)建實(shí)例對(duì)象麻昼。self參數(shù)指向了這個(gè)正在被創(chuàng)建的對(duì)象本身奠支。當(dāng)在類聲明里定義__init__()
方法時(shí),第一個(gè)參數(shù)必須為self抚芦。name為對(duì)象的一個(gè)屬性倍谜。
上面的代碼做了以下工作
創(chuàng)建Person類的定義
在內(nèi)存中實(shí)例化(創(chuàng)建)一個(gè)新的對(duì)象
調(diào)用對(duì)象的__init__方法,將新創(chuàng)建的對(duì)象作為self傳入叉抡,并將另一個(gè)參數(shù)('Elmer Fudd')作為那么傳
將name的值存入對(duì)象
返回這個(gè)新的對(duì)象
將名字hunter與這個(gè)對(duì)象關(guān)聯(lián)
這個(gè)新對(duì)象與任何其他的 Python 對(duì)象一樣枢劝。你可以把它當(dāng)作列表、元組卜壕、字典或集合中的 元素您旁,也可以把它當(dāng)作參數(shù)傳遞給函數(shù),或者把它做為函數(shù)的返回結(jié)果
在類的定義中轴捎, __init__
并不是必須的鹤盒,只有當(dāng)需要區(qū)分由該類創(chuàng)建的不同對(duì)象時(shí)蚕脏,才需要指定__init__
方法。
繼承
繼承能夠?qū)崿F(xiàn)代碼的有效復(fù)用侦锯。我們習(xí)慣的將原始的類稱為父類驼鞭,超類或者基類,將新的類稱作孩子類尺碰,子類或衍生類挣棕。
通過(guò)一個(gè)栗子了解繼承:
class Car():
def exclaim(self):
print("I'm a Car!")
class Yugo(Car):
pass
give_me_a_car = Car()
give_me_a_yugo = Yugo()
give_me_a_car.exclaim()
give_me_a_yugo.exclaim()
I'm a Car!
I'm a Car!
覆蓋方法
對(duì)父類的方法進(jìn)行覆蓋重新后重新生成對(duì)象,調(diào)用方法
class Car():
def exclaim(self):
print("I'm a Car!")
class Yugo(Car):
def exclaim(self):
print("I'm a Yugo! Much like a Car, but more Yugo-ish.")
give_me_a_car = Car()
give_me_a_yugo = Yugo()
give_me_a_car.exclaim()
give_me_a_yugo.exclaim()
I'm a Car!
I'm a Yugo! Much like a Car, but more Yugo-ish.
新創(chuàng)建的子類自動(dòng)繼承了父類的所有信息亲桥,通過(guò)重寫(xiě)父類的方法洛心,能夠?qū)崿F(xiàn)方法的覆蓋。
在子類中能夠覆蓋任何父類的方法题篷,包括__init__()
词身。下面是修改__init__()
。
我們創(chuàng)建以Person類番枚,在創(chuàng)建兩個(gè)子類MDPerson和JDPerson:
class Person():
def __init__(self,name):
self.name = name
class MDPerson(Person):
def __init__(self,name):
self.name = name
class JDPerson(Person):
def __init__(self,name):
self.name = name
person = Person('Fudd')
doctor = MDPerson('Fudd')
lawyer = JDPerson('Fudd')
print(person.name)#結(jié)果 Fudd
print(doctor.name)#結(jié)果Doctor:Fudd
print(lawyer.name)#結(jié)果Fudd:Esquire
在上面的栗子中法严,子類的初始方法__init__()
接受的參數(shù)和父類Person一樣,但是存儲(chǔ)到對(duì)象內(nèi)部name特性的值卻不同葫笼。
添加新方法
子類可以添加父類沒(méi)有的方法深啤,當(dāng)父類調(diào)用子類的方法的時(shí)候會(huì)報(bào)錯(cuò)。
class Car():
def exclaim(self):
print("I'm a car")
class Yugo(Car):
def exclaim(self):
print("I'm a Yugo! Much like a Car, but more Yugo-ish")
def need_a_push(self):
print("A little help here?")
give_me_a_car = Car()
give_me_a__yugo = Yugo()
give_me_a__yugo.need_a_push()#結(jié)果 A little help here?give_me_a_car.need_a_push()#結(jié)果
Traceback (most recent call last): File "G:/pyCharm/weather.py", line 12, in <module> give_me_a_car.need_a_push()AttributeError: 'Car' object has no attribute 'need_a_push'
使用super從父類得到幫助
上面我們完成了在子類中重新覆蓋父類的方法路星,除此之外我們還可以使用super()來(lái)調(diào)用父類的方法墓塌。
下面的小栗子將會(huì)定義一個(gè)新的類EmailPerson,用于表示有電子郵箱的Person奥额。
class Person():
def __init__(self,name):
self.name = nameclass
EmailPerson(Person):
def __init__(self,name,email):
super().__init__(name)
self.email = email
bob = EmailPerson('BObFraples','bob@frapples.com')
print(bob.name)
BOb Fraples
print(bob.email)
bob@frapples.com
在子類中定義__init__()
方法時(shí)候,父類的__init__()
方法會(huì)被覆蓋访诱。因此垫挨,在子類中,父類的初始化方法并不會(huì)被自動(dòng)調(diào)用触菜,我們必須顯式調(diào)用它九榔。以上代碼做了:
- 通過(guò)super()方法獲取了父類Person的定義
- 子類的
__init__()
調(diào)用了Person.__init__()
方法。它會(huì)自動(dòng)的將self參數(shù)傳遞給父類涡相。因此哲泊,我們只需輸入其余的參數(shù)即可。在上面的栗子中催蝗,Person()能夠接受的其余參數(shù)是name切威。 - self.email = email 使子類和父類有了區(qū)別
- 創(chuàng)建EmailPerson類對(duì)象,然后訪問(wèn)name和email屬性
為什么不像下面這樣定義 EmailPerson 類呢丙号?
class EmailPerson(Person):
def __init__(self, name, email):
self.name = name
self.email = email
確實(shí)可以這么做先朦,但這有悖我們使用繼承的初衷缰冤。我們應(yīng)該使用 super() 來(lái)讓 Person 完成 它應(yīng)該做的事情,就像任何一個(gè)單純的 Person 對(duì)象一樣喳魏。除此之外棉浸,不這么寫(xiě)還有另一個(gè) 好處:如果 Person 類的定義在未來(lái)發(fā)生改變,使用 super() 可以保證這些改變會(huì)自動(dòng)反映 到 EmailPerson 類上刺彩,而不需要手動(dòng)修改迷郑。
self的自辯
Python中必須把self設(shè)置為實(shí)例方法的第一個(gè)參數(shù)。Python使用self參數(shù)來(lái)找到正確的對(duì)象所包含的特性和方法创倔。
還記得前面例子中的 Car 類嗎嗡害?再次調(diào)用 exclaim() 方法:
car = Car()
car.exclaim()
I'm a Car!
Python 在背后做了以下兩件事情:
- 查找car對(duì)象所屬的類(Car)
- 把car對(duì)象作為self參數(shù)傳給Car類所包含的exclaim()方法
使用屬性對(duì)特性進(jìn)行訪問(wèn)和設(shè)置
Python里所有特性都是公開(kāi)的,不過(guò)我們可以設(shè)置屬性對(duì)特性進(jìn)行設(shè)置和訪問(wèn)三幻。
注意:我們?cè)谶@里將property譯作屬性就漾,將attribute譯作特性#
在下面的栗子中,我們定義一個(gè)duck類念搬,僅僅包含一個(gè)hidden_name特性抑堡。我們不希望別人直接訪問(wèn)這兩個(gè)特性,因此定義兩個(gè)方法:getter方法和setter方法朗徊,并將這兩個(gè)方法設(shè)置為name屬性首妖。
class Duck():
def __init__(self,input_name):
self.hidden_name = input_name
def get_name(self):
print('insert the getter')
return self.hidden_name
def set_name(self,input_name):
print('insert the setter')
self.hidden_name = input_name
name = property(get_name,set_name)
fowl = Duck('Howard')
#當(dāng)我們嘗試訪問(wèn)對(duì)象的name特性時(shí)候,get_name()會(huì)被自動(dòng)調(diào)用
print(fowl.name)
#也可以顯式的調(diào)用get_name()
print(fowl.get_name())
#當(dāng)對(duì)name屬性進(jìn)行賦值的時(shí)候爷恳,set_name()會(huì)被自動(dòng)調(diào)用
fowl.name = 'Daffy'print(fowl.name)
#也可以顯式的調(diào)用set_name()
fowl.set_name = 'Daffy'
print(fowl.name)
另一種定義屬性的方法是使用修飾符(decorator)有缆。下面的栗子會(huì)定義兩個(gè)不同的方法,它們的的名字都叫name()温亲,但包含不同的修飾符:
- @property棚壁,用于指示getter方法
- @name.setter,用于指示setter方法
代碼:
class Duck():
def __init__ (self,input_name):
self.hidden_name = input_name
@property
def name(self):
print('inside the getter')
return self.hidden_name
#函數(shù)名相同栈虚,但是參數(shù)不同
@name.setter
def name(self,input_name):
print('inside the setter')
self.hidden_name = input_name
fowl = Duck('Howard')
#我們?nèi)匀豢梢韵裰耙粯釉L問(wèn)特性袖外,只是沒(méi)有了get_name()和set_name()方法。
print(fowl.name)
fowl.name = 'Donald'
print(fowl.name)
注意:#這里我們?nèi)匀豢梢酝ㄟ^(guò)fowl.hidden_name 進(jìn)行讀寫(xiě)操作
之前的栗子我們使用name屬性指向類中存儲(chǔ)的某一特性魂务,除此之外是曼验,屬性還可以指向一個(gè)計(jì)算結(jié)果值。我們定義一個(gè)circle類粘姜,它包含radius特性以及一個(gè)計(jì)算屬性diameter:
class Circle():
def __init__(self,radius):
self.radius = radius
@property
def diameter(self):
return 2 * self.radius
c = Circle(5)
print(c.radius)
#可以像訪問(wèn)特性(例如radius)一樣訪問(wèn)屬性diameter:
print(c.diameter)
#如果我們沒(méi)有指定某一特性的setter屬性(@diameter.setter)鬓照,那么無(wú)法從類的外部對(duì)它的值進(jìn)行設(shè)置。對(duì)于只讀的特性非常有用孤紧。
c.diameter = 20
Traceback (most recent call last):
File "G:/pyCharm/weather.py", line 10, in <module>
c.diameter = 20
AttributeError: can't set attribute
使用名稱重整保護(hù)私有特性
Python對(duì)那些需要刻意隱藏在類內(nèi)部的特性有自己的命名規(guī)范:由連續(xù)的兩個(gè)下劃線開(kāi)頭(__)豺裆。
我們把之前的hidden_name改名為_(kāi)_name:
class Duck():
def __init__ (self,input_name):
self.__name = input_name
@property
def name(self):
print('inside the getter')
return self.__name
#函數(shù)名相同,但是參數(shù)不同
@name.setter
def name(self,input_name):
print('inside the setter')
self.__name = input_name
#代碼能夠正常工作
fowl = Duck('Howard')
fowl.name
fowl.name = 'Donald'
fowl.name
#但是此時(shí)我們無(wú)法在外部訪問(wèn)__name特性了:
print(fowl.__name)
Traceback (most recent call last):
File "G:/pyCharm/sources/daily.py", line 13, in <module>
print(fowl.__name)
AttributeError: 'Duck' object has no attribute '__name'
這種命名規(guī)范本質(zhì)上并沒(méi)有把特性變成私有号显,但 Python 確實(shí)將它的名字重整了留储,讓外部 的代碼無(wú)法使用翼抠。名稱重整是怎么實(shí)現(xiàn)的:
fowl._Duck__name
'Donald'
我們并沒(méi)有得到 inside the getter,成功繞過(guò)了 getter 方法获讳。盡管如我們所 見(jiàn)阴颖,這種保護(hù)特性的方式并不完美,但它確實(shí)能在一定程度上避免我們無(wú)意或有意地對(duì)特 性進(jìn)行直接訪問(wèn)丐膝。
方法的類型
有些數(shù)據(jù)(特性)和函數(shù)(方法)是類的一部分量愧,還有一些是由類創(chuàng)建的實(shí)例的一部分。
在類的定義中帅矗,以 self 作為第一個(gè)參數(shù)的方法都是實(shí)例方法(instance method)偎肃。它們?cè)?創(chuàng)建自定義類時(shí)最常用。實(shí)例方法的首個(gè)參數(shù)是 self浑此,當(dāng)它被調(diào)用時(shí)累颂,Python 會(huì)把調(diào)用該 方法的對(duì)象作為 self 參數(shù)傳入。
與之相對(duì)凛俱,類方法(class method)會(huì)作用于整個(gè)類紊馏,對(duì)類作出的任何改變會(huì)對(duì)它的所有實(shí) 例對(duì)象產(chǎn)生影響。在類定義內(nèi)部蒲犬,用前綴修飾符 @classmethod 指定的方法都是類方法朱监。與 實(shí)例方法類似,類方法的第一個(gè)參數(shù)是類本身原叮。在 Python 中赫编,這個(gè)參數(shù)常被寫(xiě)作 cls,因 為全稱 class 是保留字奋隶,在這里我們無(wú)法使用擂送。下面的例子中,我們?yōu)轭?A 定義一個(gè)類方 法來(lái)記錄一共有多少個(gè)類 A 的對(duì)象被創(chuàng)建:
class A():
count = 0
def __init__(self):
A.count += 1
def exclaim(self):
print("I'm an A")
@classmethod
def kids(cls):
print("A has",cls.count,"little objects.")
easy_a = A()
breezy_a = A()
wheezy_a = A()
A.kids()#A has 3 little objects.
上面的代碼中唯欣,我們使用的是 A.count(類特性)嘹吨,而不是 self.count(可能是對(duì)象 的特性)。在 kids() 方法中黍聂,我們使用的是 cls.count,它與 A.count 的作用一樣身腻。
類定義中的方法還存在著第三種類型产还,它既不會(huì)影響類也不會(huì)影響類的對(duì)象。它們出現(xiàn)在 類的定義中僅僅是為了方便嘀趟,否則它們只能孤零零地出現(xiàn)在代碼的其他地方脐区,這會(huì)影響代 碼的邏輯性。這種類型的方法被稱作靜態(tài)方法(static method)她按,用@staticmethod修飾牛隅,它既不需要self參數(shù)也不需要class參數(shù)炕柔。
class Coyote():
@staticmethod
def commercial():
print('This CoyoteWeapon has been brought to you by Acme')
#我們甚至不用創(chuàng)建任何Coyote類的對(duì)象就可以調(diào)用這個(gè)方法
Coyote.commercial()
鴨子類型
Python對(duì)實(shí)現(xiàn)多態(tài)(polymorphsim)要求十分寬松,意味著我們可以對(duì)不同的對(duì)象調(diào)用同名的操作媒佣,甚至不用管這些對(duì)象的類型是什么匕累。
我們來(lái)為三個(gè) Quote 類設(shè)定同樣的初始化方法 init(),然后再添加兩個(gè)新函數(shù):
- who()返回保存的person字符串的值
- says()返回保存的words字符串的內(nèi)容默伍,并填上指定的標(biāo)點(diǎn)符號(hào)欢嘿。
代碼如下:
class Quote():
def __init__(self,person,words):
self.person = person
self.words = words
def who(self):
return self.person
def says(self):
return self.words + '.'
class QuestionQuote(Quote):
def says(self):
return self.words + '?'
class ExclamationQuote(Quote):
def says(self):
return self.words + '!'
#接下來(lái)創(chuàng)建一些對(duì)象
hunter = Quote('Alili',"I'm hunting wabbits")
print(hunter.who(),"says:",hunter.says())
#Alili says: I'm hunting wabbits.
hunted1 = QuestionQuote('Bugs Bunny', "What's up, doc")
print(hunted1.who(), 'says:', hunted1.says())
#Bugs Bunny says: What's up, doc?
hunted2 = ExclamationQuote('Daffy Duck', "It's rabbit season")
print(hunted2.who(),"says:",hunted2.says())
#Daffy Duck says: It's rabbit season!
我們不需要改變 QuestionQuote 或者 ExclamationQuote 的初始化方式,因此沒(méi)有覆蓋它們 的 __init__()
方法也糊。Python 會(huì)自動(dòng)調(diào)用父類 Quote 的初始化函數(shù) __init__()
來(lái)存儲(chǔ)實(shí)例 變量 person 和 words炼蹦,這就是我們可以在子類 QuestionQuote 和 ExclamationQuote 的對(duì)象 里訪問(wèn) self.words 的原因
三個(gè)不同版本的 says() 為上面三種類提供了不同的響應(yīng)方式,這是面向?qū)ο蟮恼Z(yǔ)言中多態(tài) 的傳統(tǒng)形式狸剃。Python 在這方面走得更遠(yuǎn)一些掐隐,無(wú)論對(duì)象的種類是什么,只要包含 who() 和 says()钞馁,你便可以調(diào)用它虑省。##我們?cè)賮?lái)定義一個(gè) BabblingBrook 類,它與我們之前的獵人獵 物(Quote 類的后代)什么的沒(méi)有任何關(guān)系
class BabblingBrook():
def who(self):
return 'Brook'
def says(self):
return 'Baabble'
brook = BabblingBrook()
#現(xiàn)在對(duì)不同對(duì)象執(zhí)行who()和says()方法指攒,其中有一個(gè)(brook)與其他類型額對(duì)象毫無(wú)關(guān)聯(lián):
def who_says(obj):
print(obj.who(),"syas:",obj.says())
who_says(hunter)
#Alili syas: I'm hunting wabbits.
who_says(hunted1)
#Bugs Bunny syas: What's up, doc?
who_says(hunted2)
#Daffy Duck syas: It's rabbit season!
who_says(brook)
#Brook syas: Baabble
特殊方法
Python中的特殊方法的名稱以雙下劃線(__)開(kāi)頭和結(jié)束慷妙。沒(méi)錯(cuò),我們已經(jīng)見(jiàn)過(guò)其中一個(gè):__ init__
允悦,它根據(jù)類的定義以及傳入的參數(shù)對(duì)新創(chuàng)建的對(duì)象進(jìn)行初始化膝擂。
假設(shè)你有一個(gè)簡(jiǎn)單的 Word 類,現(xiàn)在想要添加一個(gè) equals() 方法來(lái)比較兩個(gè)詞是否一致隙弛, 忽略大小寫(xiě)架馋。也就是說(shuō),一個(gè)包含值 'ha' 的 Word 對(duì)象與包含 'HA' 的是相同的全闷。
下面的代碼是第一次嘗試叉寂,創(chuàng)建一個(gè)普通方法 equals()。self.text 是當(dāng)前 Word 對(duì)象所包 含的字符串文本总珠,equals() 方法將該字符串與 word2(另一個(gè) Word 對(duì)象)所包含的字符串 做比較:
class Word():
def __init__(self,text):
self.text = text
def equals(self,word2):
return self.text.lower() == word2.text.lower()
#創(chuàng)建三個(gè)包含不同字符串的對(duì)象
first = Word('ha')
second = Word('HA')
third = Word('eh')
#進(jìn)行比較
print(first.equals(second))#True
print(first.equals(third))#False
我們成功定義了 equals() 方法來(lái)進(jìn)行小寫(xiě)轉(zhuǎn)換并比較屏鳍。但試想一下,如果能通過(guò) if first == second 進(jìn)行比較的話豈不更妙局服?這樣類會(huì)更自然钓瞭,表現(xiàn)得更像一個(gè) Python 內(nèi)置的類。 把前面例子中的 equals() 方法的名稱改為 __eq__()
:
class Word():
def __init__(self,text):
self.text = text
def __eq__(self,word2):
return self.text.lower() == word2.text.lower()
#創(chuàng)建三個(gè)包含不同字符串的對(duì)象
first = Word('ha')
second = Word('HA')
third = Word('eh')
#進(jìn)行比較
print(first == second)#True
print(first == third)#False
這里我們僅僅將方法名修改為 eq()很神奇的就出現(xiàn)了淫奔。
和比較相關(guān)的魔術(shù)方法
方法名 使用
`__eq__(self, other)` self == other
`__ne__(self, other)` self != other
`__lt__(self, other)` self < other
`__gt__(self, other)` self > other
`__le__(self, other)` self <= other
`__ge__(self, other)` self >= other
和數(shù)學(xué)相關(guān)的黑魔法
方法名 使用
`__add__(self, other)` self + other
`__sub__(self, other)` self - other
`__mul__(self, other) ` self * other
`__?oordiv__(self, other)` self // other
`__truediv__(self, other)` self / other
`__mod__(self, other)` self % other
`__pow__(self, other)` self ** other
不僅數(shù)字類型可以使用像 +(魔術(shù)方法 __add__()
)和 -(魔術(shù)方法 __sub__()
)的數(shù)學(xué)運(yùn)算 符山涡,一些其他的類型也可以使用。例如,Python 的字符串類型使用 + 進(jìn)行拼接鸭丛,使用 * 進(jìn) 行復(fù)制
其他種類的魔術(shù)方法
方法名 使用
`__str__(self)` str(self)
`__repr__(self)` repr(self)
`__len__(self)` len(self)
除了 __init__()
外竞穷,你會(huì)發(fā)現(xiàn)在編寫(xiě)類方法時(shí)最常用到的是__str__()
,它用于定義如何 打印對(duì)象信息鳞溉。print() 方法瘾带,str() 方法都會(huì)用到__str__()
。交互式解釋器則用 __repr__()
方法輸出變量穿挨。如果在你的類 既沒(méi)有定義__str__()
也沒(méi)有定義 __repr__()
月弛,Python 會(huì)輸出類似下面這樣的默認(rèn)字符串:
first = Word('ha')
first
<__main__.Word object at 0x1006ba3d0>
print(first)
<__main__.Word object at 0x1006ba3d0>
我們將 `__str__()` 和 `__repr__() `方法都添加到 Word 類里,讓輸出的對(duì)象信息變得更好看些:
class Word():
def __init__(self, text):
self.text = text
def __eq__(self, word2):
return self.text.lower() == word2.text.lower()
def __str__(self):
return self.text
def __repr__(self):
return 'Word("' self.text '")'
first = Word('ha')
first # uses __repr__
Word("ha")
print(first) # uses __str__
ha
組合
如果你想要?jiǎng)?chuàng)建的子類在大多數(shù)情況下的行為都和父類相似的話(子類是父類的一種特 殊情況科盛,它們之間是 is-a 的關(guān)系)帽衙,使用繼承是非常不錯(cuò)的選擇。建立復(fù)雜的繼承關(guān)系確 實(shí)很吸引人贞绵,但有些時(shí)候使用組合(composition)或聚合(aggregation)更加符合現(xiàn)實(shí)的 邏輯(x 含有 y厉萝,它們之間是 has-a 的關(guān)系)。一只鴨子是鳥(niǎo)的一種(is-a)榨崩,它有一條尾巴 (has-a)谴垫。尾巴并不是鴨子的一種,它是鴨子的組成部分母蛛。下個(gè)例子中翩剪,我們會(huì)建立 bill 和 tail 對(duì)象,并將它們都提供給 duck 使用:
class Bill():
def __init__(self,description):
self.description = description
class Tail():
def __init__(self,length):
self.length = length
class Duck():
def __init__(self,bill,tail):
self.bill = bill
self.tail = tail
def about(self):
print('This duck has a',bill.description,'bill and a',tail.length,'tail')
tail = Tail('long')
bill = Bill('wide orage')
duck = Duck(bill,tail)
duck.about()
#結(jié)果This duck has a wide orage bill and a long tail
注:本文內(nèi)容來(lái)自《Python語(yǔ)言及其應(yīng)用》歡迎購(gòu)買原書(shū)閱讀