面向?qū)ο缶幊淌亲钣行У能浖帉懛椒ㄖ?。在面向?qū)ο缶幊讨?,你編寫表示現(xiàn)實(shí)世界中的事物和情景的類,并基于這些類來創(chuàng)建對象。編寫類時(shí),定義一個(gè)大類對象都有的通用行為?;陬悇?chuàng)建對象時(shí),每個(gè)對象都自動(dòng)具備這種通用行為,然后可根據(jù)需要賦予每個(gè)對象獨(dú)特的個(gè)性。根據(jù)類來創(chuàng)建對象被稱為實(shí)例化,這讓你能夠使用類的示例。
一、創(chuàng)建和使用類
使用類幾乎可以模擬任何東西。
1、創(chuàng)建類
dog.py
class Dog():
"""一次模擬小狗的簡單測試"""
def __init__(self,name,age):
"""初始化屬性name和age"""
self.name = name
self.age = age
def sit(self):
"""模擬小狗被命令時(shí)蹲下"""
print(self.name.title() + " is now sitting."
注:
- 根據(jù)約定,首字母大寫的名稱指的是類,這個(gè)類定義中的括號是空的,因?yàn)槲覀円獜目瞻讋?chuàng)建這個(gè)類。
- 三引號引起來的是文檔字符串,對這個(gè)類的功能進(jìn)行描述。
- 方法
__init__()是一個(gè)特殊的方法,每當(dāng)你根據(jù)類創(chuàng)建新的實(shí)例時(shí),Python都會(huì)自動(dòng)運(yùn)行它。開頭和結(jié)尾各有兩個(gè)下劃線,旨在避免Python默認(rèn)方法與普通方法發(fā)送名稱沖突。形參self必不可少,還必須位于其他形參的前面。 - 以
self為前綴的變量都可供類中的所有方法使用。
在Python 2.7中國創(chuàng)建類時(shí),應(yīng)在括號內(nèi)包含單詞object
class ClassName(object):
2、根據(jù)類創(chuàng)建實(shí)例
class Dog():
--snip--
my_dog = Dog('Bob',2)
print("My dog's name is " + my_dog.name.title() +".")
約定:首字母大寫的名稱指的是類,小寫的名稱指的是根據(jù)類創(chuàng)建的實(shí)例。
① 訪問屬性(句點(diǎn)表示法)
my_dog.name
② 調(diào)用方法(句點(diǎn)表示法)
my_dog.sit()
③ 創(chuàng)建多個(gè)實(shí)例
my_dog = Dog('Bob',2)
your_dog = Dog('Mei',3)
二、使用類和實(shí)例
類編寫好之后,你的大部分時(shí)間都將花在使用根據(jù)類創(chuàng)建的實(shí)例上。你需要執(zhí)行的一個(gè)重要任務(wù)是修改實(shí)例的屬性,可以直接修改實(shí)例的屬性,也也可以編寫方法以特定的方式進(jìn)行修改。
1、給屬性指定默認(rèn)值
class Dog():
"""一次模擬小狗的簡單測試"""
def __init__(self,name,age):
"""初始化屬性name和age"""
self.name = name
self.age = age
self.color = 'yellow'
def sit(self):
"""模擬小狗被命令時(shí)蹲下"""
print(self.name.title() + " is now sitting."
2、修改屬性的值
① 直接修改屬性的值
要修改屬性的值,最簡單的方式時(shí)通過實(shí)例直接訪問它,然后修改屬性值。
my_dog.color = 'red'
② 通過方法修改屬性的值
將要修改的值傳遞給一個(gè)方法,由它在內(nèi)部進(jìn)行修改。
class Dog():
--snip--
def update_color(self,color):
"""修改寵物的顏色"""
self.color = 'color'
③ 通過方法對屬性的值進(jìn)行遞增
有時(shí)候需要將屬性值遞增特定的量,而不是將其設(shè)置為全新的值。
三、繼承
編寫類時(shí),并非總是要從空白開始。如果你要編寫的類是一個(gè)現(xiàn)成類的特殊版本,可使用繼承。一個(gè)類繼承另一個(gè)類,它將自動(dòng)獲得另一個(gè)類的所有屬性和方法。原來的類稱為父類(超類),新類稱為子類。子類繼承了其父類的所有屬性和方法,同時(shí)還可以定義自己的屬性和方法。
1、子類的方法 __ init __ ()
class Dog():
--snip--
class BabyDog(Dog):
"""嬰兒狗的特殊之處"""
def __init__(self,name,age):
"""初始化父類的屬性"""
super().__init__(name,age)
注:
- 創(chuàng)建子類時(shí),父類必須包含在當(dāng)前文件中,且位于子類的前面。
- 定義子類時(shí),必須在括號內(nèi)指定父類的名稱。方法
__init__()接受創(chuàng)建父類實(shí)例所需的信息。 -
super()是一個(gè)特殊的函數(shù),幫助Python將父類和子類關(guān)聯(lián)起來。
2、python 2.7中的繼承
- 定義父類時(shí)在括號內(nèi)指定object;
- 函數(shù)
super()需要兩個(gè)實(shí)參:子類名和對象self。
class Dog(object):
def __init__(self,name,age):
--snip--
class BabyDog(Dog):
def __init__(self,name,age):
super(Dog,self).__init__(name,age)
--snip--
3、給子類定義屬性和方法
class Dog():
--snip--
class BabyDog(Dog):
"""嬰兒狗的特殊之處"""
def __init__(self,name,age,mother_name):
"""初始化父類的屬性,再初始化嬰兒狗的特有屬性"""
super().__init__(name,age)
self.mother_name = mother_name
def show_mother_name(self,mother_name):
"""打印嬰兒狗的麻麻的名字"""
print("This baby dog's name is " + self.name +" and it's mother is "
+ self.mother_name + ".")
4、重寫父類的方法
對于父類的方法,只要它不符合子類模擬的實(shí)物的行為,都可對其進(jìn)行重寫。為此,可在子類中定義一個(gè)與要重寫父類方法同名的方法。這樣,Python將不會(huì)考慮這個(gè)父類方法,而只關(guān)注你在子類中定義的響應(yīng)方法。
5、將實(shí)例用作屬性
使用代碼模擬實(shí)物時(shí),你可能會(huì)發(fā)現(xiàn)自己給類添加的細(xì)節(jié)越來越多:屬性和方法清單以及文件都越來越長。在這種情況下,可能需要將類的一部分作為一個(gè)獨(dú)立的類提取出來??蓪⒋笮皖惒鸱殖啥鄠€(gè)協(xié)同工作的小類。
class Car():
--snip--
class Battery():
--snip-
class ElectricCar(Car):
"""電動(dòng)汽車的獨(dú)特之處"""
def __init__(self,make,modle,year):
super().__init__(make,modle,year)
self.battery = Battery()
在ElectricCar類中,添加了一個(gè)名為self.battery的屬性,這行代碼讓Python創(chuàng)建一個(gè)新的Battery實(shí)例,并將該實(shí)例存儲(chǔ)在屬性self.battery中。每當(dāng)方法__init__()被調(diào)用時(shí),都將執(zhí)行該操作。因此現(xiàn)在每個(gè)ElectricCar實(shí)例都包含一個(gè)自動(dòng)創(chuàng)建的Battery實(shí)例。
四、導(dǎo)入類
隨著你不斷地給類添加功能,文件可能變得很長,為此,可將類存儲(chǔ)在模塊中,然后在主程序中導(dǎo)入所需的模塊。
1、導(dǎo)入單個(gè)類
dog.py
"""一個(gè)可用于表示狗的類"""
class Dog():
--snip--
注:三引號引起來的是模塊級文檔字符串,對該模塊的內(nèi)容進(jìn)行簡單的描述。
my_dog.py
from dog import Dog
my_dog = Dog('bob',2)
2、在一個(gè)模塊中存儲(chǔ)多個(gè)類
雖然同一個(gè)模塊中的類之間應(yīng)存在某種相關(guān)性,但可根據(jù)需要在一個(gè)模塊中存儲(chǔ)任意數(shù)量的類。
car.py
"""一組用于表示燃油汽車和電動(dòng)汽車的類"""
class Car():
--snip--
class Battery():
--snip--
class ElectricCar(Car):
--snip--
3、從一個(gè)模塊中導(dǎo)入多個(gè)類
my_cars.py
from car import Car,ElectricCar
4、導(dǎo)入整個(gè)模塊
導(dǎo)入整個(gè)模塊,再使用句點(diǎn)表示法訪問需要的類。由于創(chuàng)建類實(shí)例的代碼都包含模塊名,因此不會(huì)與當(dāng)前文件使用的任何名稱發(fā)生沖突。
import car
my_beetle = car.Car('volkswagen','beetle',2016)
my_tesla = car.ElectricCar('tesla','roadster',2017)
5、導(dǎo)入模塊中的所有類
from module_name import *
但是,不推薦使用這種導(dǎo)入方法。
6、在一個(gè)模塊中導(dǎo)入另一個(gè)模塊
有時(shí)候需要將類分散到多個(gè)模塊中,一面模塊過大,或在同一個(gè)模塊中國存儲(chǔ)不相關(guān)的類。此時(shí),可能一個(gè)模塊的類依賴另一個(gè)模塊中的類。
electric_car.py
"""一組可用來表示電動(dòng)汽車的類"""
from car import Car
class ElectricCar(Car):
--snip--
car.py
"""一個(gè)可用來表示汽車的類"""
class Car():
--snip--
my_cars.py
from car import Car
from electric_car import ElectricCar
--snip--
五、類編碼風(fēng)格
- 類名應(yīng)采用駝峰命名法。即將類名中的每個(gè)單詞的首字母都大寫,而不使用下劃線。實(shí)例名和模塊名都采用小寫格式,并在單詞之間加上下劃線。
- 對于每個(gè)類,都應(yīng)緊跟在類定義后面包含一個(gè)文檔字符串。這種文檔字符串簡要地描述類的功能,并遵循編寫函數(shù)的文檔字符串時(shí)采用的格式約定。每個(gè)模塊也都應(yīng)該包含一個(gè)文檔字符串,對其中的類可用于做什么進(jìn)行描述。
- 可使用空行來組織代碼,但不要濫用。在類中,可使用一個(gè)空行來分隔方法;而在模塊中,可使用兩個(gè)空行來分隔類。
- 需要同時(shí)導(dǎo)入標(biāo)準(zhǔn)庫中的模塊和你編寫的模塊時(shí),先編寫導(dǎo)入標(biāo)準(zhǔn)庫模塊的import語句,再添加一個(gè)空行,然后編寫導(dǎo)入你自己編寫的模塊的import語句。