類(lèi)
面向?qū)ο缶幊淌亲钣行У能浖帉?xiě)方法之一
在面向?qū)ο缶幊讨械咔帉?xiě)表示現(xiàn)實(shí)世界中的事物和情景的類(lèi)削锰,并基于這些類(lèi)來(lái)創(chuàng)建對(duì)象,根據(jù)類(lèi)來(lái)創(chuàng)建對(duì)象被稱(chēng)為實(shí)例化毕莱,這讓你能夠使用類(lèi)的實(shí)例器贩;
理解面向?qū)ο缶幊逃兄谙癯绦騿T一樣看世界,還可以幫助自己明白編寫(xiě)的代碼朋截,使你與其他程序員合作更輕松。
1.1部服、創(chuàng)建和使用類(lèi)
使用類(lèi)幾乎可以模擬任何東西唆姐,類(lèi)名必須大寫(xiě)瘫想,一個(gè)類(lèi)由方法和屬性組成,類(lèi)中的函數(shù)稱(chēng)為方法,可以通過(guò)實(shí)例訪(fǎng)問(wèn)的變量稱(chēng)為屬性
1.1.1瑞眼、創(chuàng)建類(lèi)
下面將創(chuàng)建一個(gè)dog 類(lèi)龙宏,這個(gè)dog 類(lèi)不是指特定的狗,而是任何的狗伤疙,對(duì)于大多數(shù)狗來(lái)說(shuō)银酗,它們都有名字和年齡,可能還會(huì)蹲下和打滾徒像,列子如下:
# 根據(jù)dog 類(lèi)創(chuàng)建的每個(gè)實(shí)例都將存儲(chǔ)名字黍特、年齡,我們還賦予了每條狗蹲下和打滾的能力
class Dog(): # 類(lèi)名必須大寫(xiě)
"""一只小狗的簡(jiǎn)單嘗試"""
def __init__(self, name, age): # 一個(gè)特殊的方法
"""初始化name和age"""
self.name = name # 屬性
self.age = age # 屬性
def sit(self): # 方法
"""模擬小狗被命令蹲下"""
print(self.name.title() + ' is now sitting.')
def roll_over(self): # 方法
"""模擬效果被命令打滾"""
print(self.name.title() + ' roll over!')
上面列子中锯蛀,init()方法衅澈,是一種特殊方法,包含了三個(gè)形參谬墙,self今布、name和age,self必不可少拭抬,而且必須在氣體形參之前部默,python調(diào)用這個(gè)方法時(shí),將自動(dòng)傳入實(shí)參self造虎,每個(gè)與類(lèi)關(guān)聯(lián)的方法調(diào)用都自動(dòng)傳遞實(shí)參self傅蹂,它是一個(gè)指向?qū)嵗旧淼囊茫寣?shí)例能訪(fǎng)問(wèn)類(lèi)中的屬性和方法算凿,調(diào)用Dog類(lèi)的init方法時(shí)份蝴,通過(guò)實(shí)參向Dog()傳遞名字和年齡,self自動(dòng)傳遞氓轰,不需要傳遞婚夫,因此只需給name和age提供值。
由一個(gè)類(lèi)可以生成無(wú)數(shù)個(gè)對(duì)象署鸡,當(dāng)一個(gè)對(duì)象的方法被調(diào)用的時(shí)候案糙,對(duì)象會(huì)將自身的引用作為第一個(gè)參數(shù)傳遞給該方法限嫌。
以self 為前綴的變量,可以供類(lèi)中所有方法使用时捌,我們可以通過(guò)類(lèi)的任何實(shí)例來(lái)訪(fǎng)問(wèn)這些變量怒医,它們是類(lèi)的屬性。
1.1.2奢讨、根據(jù)類(lèi)創(chuàng)建實(shí)例
根據(jù)類(lèi)可以創(chuàng)建無(wú)數(shù)個(gè)實(shí)例對(duì)象(instance object)稚叹,也稱(chēng)為類(lèi)的實(shí)例化:
下面來(lái)創(chuàng)建一個(gè)表示特定的狗的實(shí)例對(duì)象:
class Dog():
--snip--
my_dog = Dog('willie', 6) # 類(lèi)的實(shí)例化(實(shí)例對(duì)象),小寫(xiě)
print("My dog's name is " + my_dog.name.title() + '.') # 訪(fǎng)問(wèn)類(lèi)的屬性name
print('My dog is ' + str(my_name.age) + ' years old.') # 訪(fǎng)問(wèn)類(lèi)的屬性age
------
My dog's name is willie.
My dog is 6 years old.
訪(fǎng)問(wèn)類(lèi)的屬性
要訪(fǎng)問(wèn)類(lèi)的屬性,可以使用句點(diǎn)表示法拿诸,如要訪(fǎng)問(wèn)name的值扒袖,可以使用(my_dog.name)的方法。
調(diào)用類(lèi)的方法
與訪(fǎng)問(wèn)屬性一樣佳镜,調(diào)用方法也可以使用句點(diǎn)表示法僚稿,如要調(diào)用sit()方法凡桥,可以使用(my_dog.sit() )
class Dog():
--snip--
my_dog = Dog('willie', 6)
my_dog.sit()
my_dog.roll_over()
-------------
willie is now sitting
willie rolled over!
創(chuàng)建多個(gè)實(shí)例
根據(jù)類(lèi)可以創(chuàng)建任意數(shù)量的實(shí)例蟀伸,條件是將每個(gè)實(shí)例都存儲(chǔ)到不同變量中,或占用列表或字典的不同位置缅刽,下面來(lái)創(chuàng)建一個(gè)名為your_dog 的實(shí)例:
class Dog():
--snip--
my_dog = Dog('willie', 6)
your_dog = Dog('lucy', 3)
your_dog.sit()
---------------
lucy is now sitting.
1.2啊掏、使用類(lèi)和實(shí)例
類(lèi)創(chuàng)建后,大部分時(shí)間都是根據(jù)類(lèi)創(chuàng)建實(shí)例衰猛,需要執(zhí)行的一個(gè)重要的任務(wù)是修改實(shí)例的屬性迟蜜,修改屬性的值可以直接修改或者以特定方式修改:
1.2.1、給屬性指定默認(rèn)值
類(lèi)中屬性都必須有初始值啡省,哪怕是0或空字符串娜睛,在有些情況下,如設(shè)置默認(rèn)值時(shí)卦睹,在方法init () 內(nèi)指定的這種初始值是可行的畦戒,如果你對(duì)某個(gè)屬性這樣做了,就無(wú)需包含為它提供初始值的形參结序。
class Car():
def __init__(self, make, model, year):
"""初始化描述汽車(chē)的屬性"""
self.make = make
self.model = model
self.year = year
def get_descriptive_name(self):
"""返回整車(chē)的描述信息"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.modle
return long_name.title()
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
------
2016 Audi A4
接下來(lái)添加一個(gè)名為odometer_reading (里程讀日险)的屬性,其初始值為0徐鹤。還添加了一個(gè)read_odometer() 的方法垃环,用于讀取汽車(chē)的里程表:
class Car():
def __init__(self, make, model, year):
"""初始化描述汽車(chē)的屬性"""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0 # 添加一個(gè)能存儲(chǔ)汽車(chē)?yán)锍绦畔⒌膶傩裕鋵傩阅J(rèn)值為0
def get_descriptive_name(self):
"""返回整車(chē)的描述信息"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.modle
return long_name.title()
def read_odometer(self): # 增加一個(gè)讀取方法用于讀取打印汽車(chē)?yán)锍绦畔? """打印一條信息指出汽車(chē)?yán)锍?""
print('This car has ' + str(self.odometer_reading) + ' miles on it.')
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer() # 調(diào)用read_odometer() 方法返敬,調(diào)用self.odometer_reading 屬性的值
------
2016 Audi A4
This car has 0 miles on it.
1.2.2遂庄、修改屬性的值
修改屬性的值,有如下三種方法:
- 直接通過(guò)實(shí)例進(jìn)行修改
- 通過(guò)方法進(jìn)行設(shè)置
- 通過(guò)方法進(jìn)行遞增(增加特定值)
直接修改
將里程數(shù)(odometer_reading)修改為23劲赠,直接通過(guò)實(shí)例調(diào)用屬性涧团,修改其值:
class Car():
--snip--
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23 # 通過(guò)實(shí)例調(diào)用屬性只磷,訪(fǎng)問(wèn)并修改其值
my_new_car.read_odometer() # 調(diào)用方法打印里程信息
------
2016 Audi A4
This car has 23 miles on it.
通過(guò)方法修改屬性的值
如果有替你更新屬性的方法,就無(wú)需直接訪(fǎng)問(wèn)屬性泌绣,而是將值傳遞給一個(gè)方法钮追,由它在內(nèi)部進(jìn)行更新。
下面添加一個(gè)名為update_odometer() 的方法阿迈,其中有一個(gè)形參元媚,用于接收里程數(shù):
class Car():
--snip--
def update_odometer(self, mileage): # 定義一個(gè)方法,用于內(nèi)部更新屬性odometer_reading 的值苗沧,其中一個(gè)形參用于接收里程數(shù)刊棕,并將其指定為屬性odometer_reading
"""將里程數(shù)讀數(shù)設(shè)置為指定值"""
"""禁止里程往回?fù)?""
if mileage >= odometer_reading: # 修改屬性前,檢查指定的數(shù)是否合理
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(32) # 調(diào)用方法待逞,并傳遞值32給形參mileage
my_new_car.read_odometer()
------------
2016 Audi A4
This car has 32 miles on it.
通過(guò)方法對(duì)屬性的值進(jìn)行遞增
有時(shí)需要將屬性值遞增特定的值甥角,而不是設(shè)置為全新的值,比如買(mǎi)了一輛二手車(chē)识樱,從購(gòu)買(mǎi)到登記期間增加了100英里的里程:
class Car():
--snip--
def update_odometer(self, mileage):
--snip--
def increment_odometer(self, miles): # 新增方法嗤无,接受一個(gè)單位為英里的數(shù)字,并將其存儲(chǔ)到屬性self.odometer_reading中
"""將里程表讀數(shù)增加特定的量"""
self.odometer_reading += miles
my_used_car = Car('subaru', 'outback', 2013)
print(my_used_car.get_rescriptive_name())
my_used_car.update_odometer(23500)
my_used_car.read_odometer()
my_used_car.increment_odometer(100)
my_used_car.read_odometer()
------
2013 Subaru Outback
This car has 23500 miles on it.
This car has 23600 miles on it.
練習(xí)
添加一個(gè)屬性number_served,默認(rèn)值為0怜庸,創(chuàng)建一個(gè)名為restaurant 的實(shí)例当犯,打印這家餐館有多少人在這家餐館就餐,然后修改這個(gè)值并打印它割疾,添加一個(gè)名為set_number_served() 的方法嚎卫,它能設(shè)置就餐人數(shù),調(diào)用它傳遞一個(gè)值宏榕,再打印這個(gè)值拓诸,添加一個(gè)名為increment_number_served() 的方法,它讓你能夠?qū)⒕筒腿藬?shù)遞增麻昼,調(diào)用它并傳遞一個(gè)這樣的值:你認(rèn)為這家餐館每天可能接待的就餐人數(shù):
class Restaurant():
"""創(chuàng)建一個(gè)Restaurant的類(lèi)奠支,里面包含餐廳名字,菜品類(lèi)型"""
def __init__(self, restaurant_name, cuisine_type):
self.restaurant_name = restaurant_name.title()
self.cuisine_type = cuisine_type
self.number_served = 0
def describe(self):
"""顯示餐館的基本信息"""
msg = self.restaurant_name + ' serves wonderful ' + self.cuisine_type + '.'
print(msg)
def open_restaurant(self):
"""顯示餐館正在營(yíng)業(yè)"""
msg = self.restaurant_name + ' is open. Come on in!'
print(msg + '\n')
def set_number_served(self, number_served):
"""顯示就餐人數(shù)"""
self.number_served = number_served
def increment_nums(self, additional_served):
"""人數(shù)遞增"""
self.number_served += additional_served
restaurant = Restaurant("alice's home", 'pizza')
restaurant.describe()
restaurant.open_restaurant()
restaurant.set_number_served(16)
print('The current number of repast is ' + str(restaurant.number_served))
restaurant.increment_nums(10)
print('The current number of repast is ' + str(restaurant.number_served))
------------------
Alice'S Home serves wonderful pizza.
Alice'S Home is open. Come on in!
The current number of repast is 16
The current number of repast is 26
1.3涌献、繼承
編寫(xiě)類(lèi)時(shí)胚宦,不是都是從空白開(kāi)始,有時(shí)要編寫(xiě)的類(lèi)是另一個(gè)現(xiàn)成的類(lèi)的特殊版本燕垃,可使用繼承枢劝。一個(gè)類(lèi)繼承另一個(gè)類(lèi)時(shí),它將自動(dòng)獲得另一個(gè)類(lèi)的所有屬性和方法卜壕,被繼承的類(lèi)稱(chēng)為基類(lèi)或父類(lèi)您旁,繼承的類(lèi)稱(chēng)為子類(lèi),子類(lèi)也可以定義自己的屬性和方法轴捎。
下面我們來(lái)創(chuàng)建一個(gè)名為 ElectricCar()的子類(lèi)鹤盒,繼承于父類(lèi)Car()蚕脏,用來(lái)描述電動(dòng)汽車(chē)的相關(guān)信息,它具備Car類(lèi)的所有功能:
class Car(): # 父類(lèi)
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
long_time = str(self.year) + ' ' + self.make + ' ' + self.model
return long_time.title()
def read_odometer(self):
print('This car has ' + str(self.odometer_reading) + ' miles on it.')
def update_odometer(self, mileage):
"""將里程表讀數(shù)設(shè)置為指定的數(shù)"""
self.odometer_reading = mileage
def increment_odometer(self, miles):
self.odometer_reading += miles
class ElectricCar(Car): # 子類(lèi)侦锯,定義子類(lèi)時(shí)驼鞭,括號(hào)內(nèi)必須指定父類(lèi)名稱(chēng)
"""電動(dòng)車(chē)的獨(dú)特之處"""
def __init__(self, make, model, year): # 方法__init__()接受創(chuàng)建父類(lèi)實(shí)例所需信息
"""初始化父類(lèi)的屬性"""
super().__init__(make, model, year) # super()是一個(gè)特殊函數(shù),可以將父類(lèi)與子類(lèi)關(guān)聯(lián)起來(lái)尺碰,它可以讓python調(diào)用父類(lèi)的方法__init__()挣棕,讓子類(lèi)實(shí)例包含父類(lèi)的所有屬性,父類(lèi)也稱(chēng)為超類(lèi)(superclass)
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
------------------------
2016 Tesla Model S
上面例子亲桥,我們首先定一個(gè)名為ElectricCar的子類(lèi)洛心,它繼承父類(lèi)Car,創(chuàng)建子類(lèi)時(shí)题篷,父類(lèi)必須在子類(lèi)之前词身,定義子類(lèi)時(shí)括號(hào)內(nèi)必須指定父類(lèi)名稱(chēng),方法init() 接受Car實(shí)例所需的信息(初始化父類(lèi)的所有屬性和方法)番枚。
super()函數(shù)是一個(gè)特殊函數(shù)法严,幫助python將父類(lèi)與子類(lèi)關(guān)聯(lián)起來(lái),自動(dòng)找到父類(lèi)的方法户辫,不需要給出父類(lèi)的名字渐夸,這行代碼讓python調(diào)用父類(lèi)的方法init()嗤锉,讓子類(lèi)實(shí)例包含父類(lèi)的所有屬性渔欢。
為子類(lèi)創(chuàng)建一個(gè)實(shí)例對(duì)象my_tesla,傳入實(shí)參瘟忱,它將調(diào)用子類(lèi)的init() 方法奥额,子類(lèi)的init() 方法將調(diào)用父類(lèi)的init() 方法。
1.3.1访诱、給子類(lèi)定義屬性和方法
繼承后垫挨,可以添加區(qū)分子類(lèi)和父類(lèi)所需的新屬性和方法,需要注意的是触菜,子類(lèi)可以添加任意數(shù)量的屬性和方法九榔,但只適用子類(lèi),如果要適用子類(lèi)和父類(lèi)涡相,那么應(yīng)該添加到父類(lèi)中哲泊。
下面為子類(lèi)ElectricCar 添加一個(gè)電動(dòng)汽車(chē)特有的屬性(電瓶),以及一個(gè)描述該屬性的方法催蝗,存儲(chǔ)電瓶的容量切威,并編寫(xiě)一個(gè)打印電瓶描述的方法:
class Car():
--snip--
class ElectricCar(Car):
""""""
def __init__(self, make, model, year):
""""""
super().__init__(make, model, year)
self.battery_size = 70 # 添加新屬性存儲(chǔ)電瓶容量,初始值為70
def describe_battery(self): # 定一個(gè)方法丙号,用于描述打印這輛車(chē)的電瓶容量信息
print('This car has a ' + str(self.battery_size) + '-kwh battery.')
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery() # 調(diào)用方法describe_battery()
------------------------
Tesla Model S 2016
This car has a 70-kwh battery.
1.3.2先朦、重寫(xiě)父類(lèi)的方法
如果父類(lèi)的方法不能滿(mǎn)足子類(lèi)的需求缰冤,可以對(duì)其進(jìn)行重寫(xiě),為此可以在子類(lèi)中定一個(gè)方法喳魏,與要重寫(xiě)的父類(lèi)方法同名棉浸,這樣python 就不會(huì)考慮這個(gè)父類(lèi)的方法,而只關(guān)注這個(gè)子類(lèi)中定義的相應(yīng)方法刺彩。
假設(shè)Car類(lèi)有一個(gè)名為fill_gas_tank()的方法涮拗,它對(duì)電動(dòng)汽車(chē)來(lái)說(shuō)沒(méi)有意義,因此你可能需要重寫(xiě)它:
class Car():
--snip--
def fill_gas_tank(self):
print('This car has a gas tank.')
class ElectricCar(Car):
--snip--
def fill_gas_tank(self): # 重寫(xiě)父類(lèi)方法fill_gas_tank(),因?yàn)楦割?lèi)的方法不能滿(mǎn)足子類(lèi)
"""電動(dòng)車(chē)沒(méi)有油箱"""
print("This car doesn't need a gas tank!")
my_tesla = ElectricCar('tesla', 'model s' 2016)
my_new_car = Car('audi', 'a4', 2016)
my_tesla.fill_gas_tank() # 父類(lèi)的方法一旦被重寫(xiě)迂苛,父類(lèi)的實(shí)例調(diào)用被重寫(xiě)的方法也會(huì)被忽略
my_new_car.fill_gas_tank()
------------------
This car doesn't need a gas tank!
This car doesn't need a gas tank!
1.3.3三热、將實(shí)例用作屬性
使用代碼模擬實(shí)物時(shí),你可能會(huì)給類(lèi)添加越來(lái)越多的細(xì)節(jié)三幻,屬性和方法以及文件越來(lái)越長(zhǎng)就漾,這種情況下可能需要將類(lèi)的一部分作為一個(gè)獨(dú)立的類(lèi)提取出來(lái),拆分成多個(gè)協(xié)同工作的小類(lèi)念搬。
給ElectricCar 類(lèi)添加細(xì)節(jié)抑堡,可能會(huì)包含很多專(zhuān)門(mén)對(duì)汽車(chē)電瓶的屬性和方法,可以將這些屬性和方法提取出來(lái)朗徊,放到另外一個(gè)名為Battery的類(lèi)中首妖,并將Battery實(shí)例用作ElectricCar類(lèi)的一個(gè)屬性:
class Car():
--snip--
class Battery(): # 定義一個(gè)新類(lèi),用于存儲(chǔ)ElectricCar的屬性和方法
"""一次模擬電動(dòng)汽車(chē)電瓶的簡(jiǎn)單嘗試"""
def __init__(self, battery_size=70): # 設(shè)置電瓶容量初始值
"""初始化電瓶的屬性"""
self.battery_size = battery_size
def describe_battery(self):
"""打印一條描述電瓶容量的消息"""
print('This car has a ' + str(self.battery_size) + '-kwh battery.')
class ElectricCar(Car):
"""電動(dòng)車(chē)的獨(dú)特之處"""
def __init__(self, make, model, year):
"""初始化父類(lèi)的屬性爷恳,再初始化電動(dòng)車(chē)的特有屬性"""
super().__init__(make, model, year)
self.battery = Battery() # 這行代碼讓python創(chuàng)建了一個(gè)新的Battery實(shí)例(由于沒(méi)有指定參數(shù)有缆,默認(rèn)值為70),并將實(shí)例存儲(chǔ)在屬性self.battert中温亲,每當(dāng)__init__()被調(diào)用時(shí)棚壁,都將執(zhí)行該操作
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery() # 調(diào)用時(shí)采用ElectricCar的實(shí)例加Battery實(shí)例的方式調(diào)用Battery中的方法
-------------------
2016 Tesla Model S
This car has a 70-kwh battery.
把子類(lèi)拆分成很多小類(lèi)去協(xié)同處理,看似多了很多步驟栈虚,但是可以避免子類(lèi)混亂不堪袖外,現(xiàn)在我們可以去拓展電動(dòng)汽車(chē)的其他信息,比如描述電瓶容量的續(xù)航里程魂务,在Battery中添加一個(gè)名為get_range ()的方法曼验,用于描述續(xù)航里程:
class Car():
--snip--
class Battery():
--snip--
def get_range(self): # 定義一個(gè)方法,用于描述打印電瓶續(xù)航里程信息
if self.battery_size == 70:
range = 240
elif self.battery_size == 85:
range = 270
msg = 'This car can go approximately ' + str(range)
msg += ' miles on a full charge.'
print(msg)
class ElectricCar(Car):
--snip--
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range() # 調(diào)用get_battery() 方法
----------------
2016 Tesla Model S
This car has a 70-kwh battery.
This car can go approximately 240 miles on a full charge.
1.4粘姜、導(dǎo)入類(lèi)
隨著我們給類(lèi)不斷添加功能鬓照,代碼、文件越來(lái)越長(zhǎng)相艇,為遵循python的總體理念颖杏,應(yīng)讓文件盡可能簡(jiǎn)潔,為此我們可以將類(lèi)存儲(chǔ)到模塊中坛芽,然后在主程序中導(dǎo)入所需的模塊即可留储。
1.4.1翼抠、導(dǎo)入單個(gè)類(lèi)
上面我們舉例寫(xiě)了一個(gè)Car類(lèi),現(xiàn)在我們把它放到一個(gè)名為car.py的文件中(模塊)获讳,再新建一個(gè)my_car.py 的文件阴颖,我們?cè)趍y_car.py 中導(dǎo)入Car 類(lèi)試試:
# car.py
class Car():
def __init__(self, make, model, year):
"""初始化汽車(chē)屬性"""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""返回整車(chē)的描述性名稱(chēng)"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odometer(self):
"""打印一條信息,指出汽車(chē)的里程"""
print('This car has ' + str(self.odometer_reading) + ' miles on it.')
def update_odometer(self, mileage):
"""將里程表讀數(shù)設(shè)置為指定的值"""
"""拒絕將里程表回?fù)?""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print('You can not roll back an odometer!')
def increment_odometer(self, miles):
"""將里程表讀數(shù)增加指定量"""
self.odometer_reading += miles
class Battery():
"""一次模擬電動(dòng)汽車(chē)電瓶的簡(jiǎn)單嘗試"""
def __init__(self, battery_size=70):
"""初始化電瓶的屬性"""
self.battery_size = battery_size
def describe_battery(self):
"""打印一條描述電瓶容量的信息"""
print('This car has a ' + str(self.battery_size) + '-kwh battery.')
def get_range(self):
"""打印一條消息丐膝,指出電瓶的續(xù)航里程"""
if self.battery_size == 70:
range_0 = 240
elif self.battery_size == 85:
range_0 = 270
msg = 'This car can go approximately ' + str(range_0)
msg += ' miles on a full charge.'
print(msg)
class ElectricCar(Car):
"""電動(dòng)車(chē)的獨(dú)特之處"""
def __init__(self, make, model, year):
"""初始化父類(lèi)的屬性,再初始化子類(lèi)的屬性"""
super().__init__(make, model, year)
self.battery = Battery()
# my_car.py
from car import Car # 從模塊car.py中導(dǎo)入Car 類(lèi)
my_new_car = Car('audi', 'a4', 2016) # Car 類(lèi)實(shí)例化量愧,傳入?yún)?shù)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
--------------------
2016 Audi A4
This car has 23 miles on it.
1.4.2、從一個(gè)模塊中導(dǎo)入多個(gè)類(lèi)
一個(gè)模塊可以存儲(chǔ)多個(gè)類(lèi)帅矗,我們可以一次導(dǎo)入一個(gè)或者多個(gè)類(lèi)到主程序中偎肃,
導(dǎo)入多個(gè)類(lèi)時(shí),類(lèi)之間用逗號(hào)分隔即可浑此,導(dǎo)入后即可根據(jù)類(lèi)創(chuàng)建任意數(shù)量的實(shí)例累颂。
如果我們要在同一個(gè)程序中創(chuàng)建普通汽車(chē)和電動(dòng)汽車(chē),就需要將Car 和 ElectricCar 類(lèi)都導(dǎo)入:
# my_car.py
from car import Car, ElectricCar # 從模塊car.py中導(dǎo)入Car和ElectricCar 類(lèi)
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
my_tesla = ElectricCar('tesla', 'model s', 2016)
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
1.4.3凛俱、導(dǎo)入整個(gè)模塊
也可以導(dǎo)入整個(gè)模塊紊馏,再使用句點(diǎn)表示法訪(fǎng)問(wèn)所需要的類(lèi),這種方法蒲犬,代碼易讀朱监,也不會(huì)與當(dāng)前文件使用的任何名稱(chēng)發(fā)生沖突:
# my_car.py
import car
my_new_car = car.Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
------------------
2016 Audi A4
1.4.4、導(dǎo)入模塊中所有類(lèi)
# 語(yǔ)法
from module_name import *
不推薦使用這種方法導(dǎo)入模塊中所有類(lèi)原叮,這樣容易導(dǎo)致名稱(chēng)方面的困惑赫编,引發(fā)難以診斷的錯(cuò)誤,應(yīng)使用導(dǎo)入模塊名篇裁,再采用句點(diǎn)表示法的方法訪(fǎng)問(wèn)沛慢。
1.4.5赡若、在一個(gè)模塊中導(dǎo)入另一個(gè)模塊
有時(shí)需要將類(lèi)分散到多個(gè)模塊中达布,以免模塊太大,或在同一模塊中存儲(chǔ)不相關(guān)的類(lèi)逾冬,將類(lèi)存儲(chǔ)到多個(gè)模塊中時(shí)黍聂,你可能會(huì)發(fā)現(xiàn)一個(gè)模塊中的類(lèi)依賴(lài)與另一個(gè)模塊中的類(lèi),這種情況下身腻,可在前一個(gè)模塊中導(dǎo)入必要的類(lèi)产还。
下面,我們將Car 類(lèi)存儲(chǔ)到模塊car.py 中嘀趟,將Battery和 ElectricCar 類(lèi)存儲(chǔ)到模塊 electric_car.py 中脐区,在調(diào)用ElectricCar 類(lèi)時(shí)需要依賴(lài)Car 類(lèi),因此我們可以在electric_car.py 中導(dǎo)入car.py她按。
# electric_car.py
"""一組可用于表示電動(dòng)汽車(chē)的類(lèi)"""
from car import Car # ElectricCar需要訪(fǎng)問(wèn)其父類(lèi)牛隅,因此我們直接將Car類(lèi)導(dǎo)入到該模塊中
class Battery():
--snip--
class ElectricCar():
--snip--
# my_car.py # 在my_car模塊中導(dǎo)入car和electric_car 模塊
from car import Car
from electric_car import ElectricCar
1.5炕柔、Python標(biāo)準(zhǔn)庫(kù)
Python標(biāo)準(zhǔn)庫(kù)是一組模塊,安裝的python都包含它媒佣,現(xiàn)在對(duì)類(lèi)有一定的了解匕累,可以使用其他程序員編寫(xiě)好的模塊,以及標(biāo)準(zhǔn)庫(kù)中的任何函數(shù)和類(lèi)默伍,為此只需一句在程序中包含一條簡(jiǎn)單的imp 語(yǔ)句欢嘿,下面來(lái)看模塊collections中的一個(gè)類(lèi)-----OrdereDict
OrdereDict 實(shí)例行為與字典幾乎一致,區(qū)別在于它記錄了添加鍵-值對(duì)的添加順序也糊,而字典不能炼蹦。
# favorite_language.py
from collections import OrderedDict
favorite_languages = OrderedDict()
favorite_languages['jen'] = 'Python'
favorite_languages['sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'java'
for name, languages in favorite_languages.items():
print(name.title() + "'s favorite language is " + languages.title() + '.')
----------------------------
Jen's favorite language is Python.
Sarah's favorite language is C.
Edward's favorite language is Ruby.
Phil's favorite language is Java.
1.6、類(lèi)編碼風(fēng)格
與類(lèi)有關(guān)的編碼風(fēng)格問(wèn)題狸剃,在編寫(xiě)復(fù)雜程序更應(yīng)遵循:
- 類(lèi)名:駝峰式命名法(如ElectricCar)框弛,即首字母大寫(xiě),而不是用下劃線(xiàn)
- 實(shí)例名:小寫(xiě)格式捕捂,單詞間使用下劃線(xiàn)
- 每個(gè)類(lèi)都應(yīng)包含一個(gè)文檔字符串瑟枫,用于描述類(lèi)的功能,每個(gè)模塊也應(yīng)有指攒。
- 空行:可用來(lái)組織代碼慷妙,但不應(yīng)濫用,類(lèi)中允悦,一個(gè)空行分隔方法膝擂,模塊中,兩個(gè)空行分隔類(lèi)隙弛。
- 需要同時(shí)導(dǎo)入標(biāo)準(zhǔn)庫(kù)中的模塊和你編寫(xiě)的模塊時(shí)架馋,先編寫(xiě)導(dǎo)入標(biāo)準(zhǔn)庫(kù)的import 語(yǔ)句,再添加一個(gè)空行全闷,然后在編寫(xiě)導(dǎo)入你自己編寫(xiě)的模塊的import 語(yǔ)句叉寂,在包含多條import 語(yǔ)句的程序中,這種做法讓人更容易明白程序使用的各個(gè)模塊來(lái)自何方总珠。
練習(xí)
模塊random 包含以各種方式生成隨機(jī)數(shù)的函數(shù)屏鳍,其中randint()返回一個(gè)位于指定范圍內(nèi)的整數(shù),創(chuàng)建一個(gè)Die 類(lèi)局服,包含一個(gè)名為sides 的屬性钓瞭,默認(rèn)值為6,編寫(xiě)一個(gè)名為 roll_die()的方法淫奔,它打印位于1和骰子面數(shù)之間的隨機(jī)數(shù)山涡,創(chuàng)建一個(gè)6 面、10面、20面的骰子鸭丛,再分別擲 10 次:
from random import randint # 導(dǎo)入random 模塊以及randint 函數(shù)
class Die():
def __init__(self, sides=6):
self.sides = sides
def roll_die(self):
return randit(1, self.sides) # 返回生成1 到self.sides 間的隨機(jī)數(shù)霍殴,不傳入?yún)?shù)就使用默認(rèn)值 6
d_6 = Die() # Die 類(lèi)實(shí)例化,6 面骰子拋擲10次
results = [] # 將結(jié)果存儲(chǔ)到 results 列表中
for roll_num in range(10):
result = d_6.roll_die()
results.append(result)
print('10 rolls of a 6-sided die:')
print(results)
d_10 = Die(sides=10) # 10 面骰子
results = []
for roll_num in range(10):
result = d_10.roll_die()
results.append(result)
print('10 rolls of a 6-sided die:')
print(results)
d_20 = Die(sides=20) # 20 面骰子
results = []
for roll_num in range(10):
result = d_10.roll_die()
results.append(result)
print('10 rolls of a 6-sided die:')
print(results)
--------------------
10 rolls of a 6-sided die:
[4, 1, 1, 1, 5, 5, 2, 2, 3, 4]
10 rolls of a 6-sided die:
[5, 2, 2, 3, 9, 4, 2, 7, 10, 8]
10 rolls of a 6-sided die:
[1, 19, 5, 18, 19, 19, 8, 10, 8, 10]