9.3.2 Python 2.7 中的繼承
在Python 2.7中,繼承語法稍有不同,ElectricCar類的定義類似于下面這樣:
class Car(object):
def __init__(self, make, model, year):
--snip--
class ElectricCar(Car):
def __init__(self, make, model, year):
super(ElectricCar, self).__init__(make, model, year)
--snip--
函數(shù)super()需要兩個實參:子類名和對象self。為幫助Python將父類和子類關(guān)聯(lián)起來,這些 實參必不可少。另外,在Python 2.7中使用繼承時,務(wù)必在定義父類時在括號內(nèi)指定object。
9.3.3 給子類定義屬性和方法
讓一個類繼承另一個類后,可添加區(qū)分子類和父類所需的新屬性和方法。
下面來添加一個電動汽車特有的屬性(電瓶),以及一個描述該屬性的方法。我們將存儲電 瓶容量,并編寫一個打印電瓶描述的方法:
class Car():
--snip--
class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
"""
電動汽車的獨特之處
初始化父類的屬性,再初始化電動汽車特有的屬性
"""
super().__init__(make, model, year)
1 self.battery_size = 70
2 def describe_battery(self):
"""打印一條描述電瓶容量的消息"""
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()
在1處,我們添加了新屬性self.battery_size,并設(shè)置其初始值(如70)。根據(jù)ElectricCar 類 創(chuàng)建的所有實例都將包含這個屬性,但所有Car實例都不包含它。在2處,我們還添加了一個名 為describe_battery()的方法,它打印有關(guān)電瓶的信息。我們調(diào)用這個方法時,將看到一條電動 汽車特有的描述:
2016 Tesla Model S
This car has a 70-kWh battery.
對于ElectricCar類的特殊化程度沒有任何限制
def ElectricCar(Car): --snip-- def fill_gas_tank(): """電動汽車沒有油箱""" print("This car doesn't need a gas tank!")
。模擬電動汽車時,你可以根據(jù)所需的準確 程度添加任意數(shù)量的屬性和方法。如果一個屬性或方法是任何汽車都有的,而不是電動汽車特有 的,就應(yīng)將其加入到Car類而不是ElectricCar類中。這樣,使用Car類的人將獲得相應(yīng)的功能,而 ElectricCar類只包含處理電動汽車特有屬性和行為的代碼。
9.3.4 重寫父類的方法
對于父類的方法,只要它不符合子類模擬的實物的行為,都可對其進行重寫。為此,可在子 類中定義一個這樣的方法,即它與要重寫的父類方法同名。這樣,Python將不會考慮這個父類方 法,而只關(guān)注你在子類中定義的相應(yīng)方法。
假設(shè)Car類有一個名為fill_gas_tank()的方法,它對全電動汽車來說毫無意義,因此你可能 想重寫它。下面演示了一種重寫方式:
def ElectricCar(Car):
--snip--
def fill_gas_tank():
"""電動汽車沒有油箱"""
print("This car doesn't need a gas tank!")
現(xiàn)在,如果有人對電動汽車調(diào)用方法fill_gas_tank(),Python將忽略Car類中的方法 fill_gas_tank(),轉(zhuǎn)而運行上述代碼。使用繼承時,可讓子類保留從父類那里繼承而來的精華, 并剔除不需要的糟粕。
9.3.5 將實例用作屬性
使用代碼模擬實物時,你可能會發(fā)現(xiàn)自己給類添加的細節(jié)越來越多:屬性和方法清單以及文 件都越來越長。在這種情況下,可能需要將類的一部分作為一個獨立的類提取出來。你可以將大 型類拆分成多個協(xié)同工作的小類。
例如,不斷給ElectricCar類添加細節(jié)時,我們可能會發(fā)現(xiàn)其中包含很多專門針對汽車電瓶 的屬性和方法。在這種情況下,我們可將這些屬性和方法提取出來,放到另一個名為Battery的 類中,并將一個Battery實例用作ElectricCar類的一個屬性:
class Car():
--snip--
1 class Battery():
"""一次模擬電動汽車電瓶的簡單嘗試"""
2 def __init__(self, battery_size=70):
"""初始化電瓶的屬性"""
self.battery_size = battery_size
3 def describe_battery(self):
"""打印一條描述電瓶容量的消息"""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
class ElectricCar(Car):
"""電動汽車的獨特之處"""
def __init__(self, make, model, year):
"""
初始化父類的屬性,再初始化電動汽車特有的屬性
"""
super().__init__(make, model, year)
4 self.battery = Battery()
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
在1處,我們定義了一個名為Battery的新類,它沒有繼承任何類。2處的方法__init__()除 self外,還有另一個形參battery_size。這個形參是可選的:如果沒有給它提供值,電瓶容量將 被設(shè)置為70。方法describe_battery()也移到了這個類中(見3)。
在ElectricCar類中,我們添加了一個名為self.battery的屬性(見4)。這行代碼讓Python 創(chuàng)建一個新的Battery實例(由于沒有指定尺寸,因此為默認值70),并將該實例存儲在屬性 self.battery中。每當方法__init__()被調(diào)用時,都將執(zhí)行該操作;因此現(xiàn)在每個ElectricCar實 例都包含一個自動創(chuàng)建的Battery實例。
我們創(chuàng)建一輛電動汽車,并將其存儲在變量my_tesla中。要描述電瓶時,需要使用電動汽車 的屬性battery:
my_tesla.battery.describe_battery()
這行代碼讓Python在實例my_tesla中查找屬性battery,并對存儲在該屬性中的Battery實例 調(diào)用方法describe_battery()。 輸出與我們前面看到的相同:
2016 Tesla Model S
This car has a 70-kWh battery.
這看似做了很多額外的工作,但現(xiàn)在我們想多詳細地描述電瓶都可以,且不會導(dǎo)致ElectricCar 類混亂不堪。下面再給Battery類添加一個方法,它根據(jù)電瓶容量報告汽車的續(xù)航里程:
class Car():
--snip--
class Battery():
--snip--
1 def get_range(self):
"""打印一條消息,指出電瓶的續(xù)航里程"""
if self.battery_size == 70:
range = 240
elif self.battery_size == 85:
range = 270
message = "This car can go approximately " + str(range)
message += " miles on a full charge."
print(message)
class ElectricCar(Car):
--snip--
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
2 my_tesla.battery.get_range()
1 處新增的方法get_range()做了一些簡單的分析:如果電瓶的容量為70kWh,它就將續(xù)航里 程設(shè)置為240英里;如果容量為85kWh,就將續(xù)航里程設(shè)置為270英里,然后報告這個值。為使用 這個方法,我們也通過汽車的屬性battery來調(diào)用它(見2)。 輸出指出了汽車的續(xù)航里程(這取決于電瓶的容量):
2016 Tesla Model S
This car has a 70-kWh battery.
This car can go approximately 240 miles on a full charge.
9.3.6 模擬實物
模擬較復(fù)雜的物件(如電動汽車)時,需要解決一些有趣的問題。續(xù)航里程是電瓶的屬性還 是汽車的屬性呢?如果我們只需描述一輛汽車,那么將方法get_range()放在Battery類中也許是合 適的;但如果要描述一家汽車制造商的整個產(chǎn)品線,也許應(yīng)該將方法get_range()移到ElectricCar 類中。在這種情況下,get_range()依然根據(jù)電瓶容量來確定續(xù)航里程,但報告的是一款汽車的續(xù) 航里程。我們也可以這樣做:將方法get_range()還留在Battery類中,但向它傳遞一個參數(shù),如 car_model;在這種情況下,方法get_range()將根據(jù)電瓶容量和汽車型號報告續(xù)航里程。
這讓你進入了程序員的另一個境界:解決上述問題時,你從較高的邏輯層面(而不是語法層 面)考慮;你考慮的不是Python,而是如何使用代碼來表示實物。到達這種境界后,你經(jīng)常會發(fā) 現(xiàn),現(xiàn)實世界的建模方法并沒有對錯之分。有些方法的效率更高,但要找出效率最高的表示法,需要經(jīng)過一定的實踐。只要代碼像你希望的那樣運行,就說明你做得很好!即便你發(fā)現(xiàn)自己不得 不多次嘗試使用不同的方法來重寫類,也不必氣餒;要編寫出高效、準確的代碼,都得經(jīng)過這樣 的過程。
9.4 導(dǎo)入類
隨著你不斷地給類添加功能,文件可能變得很長,即便你妥善地使用了繼承亦如此。為遵循 Python的總體理念,應(yīng)讓文件盡可能整潔。為在這方面提供幫助,Python允許你將類存儲在模塊 中,然后在主程序中導(dǎo)入所需的模塊。
9.4.1 導(dǎo)入單個類
下面來創(chuàng)建一個只包含Car類的模塊。這讓我們面臨一個微妙的命名問題:在本章中,已經(jīng) 有一個名為car.py的文件,但這個模塊也應(yīng)命名為car.py,因為它包含表示汽車的代碼。我們將這 樣解決這個命名問題:將Car類存儲在一個名為car.py的模塊中,該模塊將覆蓋前面使用的文件car.py。從現(xiàn)在開始,使用該模塊的程序都必須使用更具體的文件名,如my_car.py。下面是模塊 car.py,其中只包含Car類的代碼:
car.py
1 """一個可用于表示汽車的類"""
class Car():
"""一次模擬汽車的簡單嘗試"""
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_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odometer(self):
"""打印一條消息,指出汽車的里程"""
print("This car has " + str(self.odometer_reading) + " miles on it.")
def update_odometer(self, mileage):
"""
將里程表讀數(shù)設(shè)置為指定的值
拒絕將里程表往回撥
"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
"""將里程表讀數(shù)增加指定的量"""
self.odometer_reading += miles
在?處,我們包含了一個模塊級文檔字符串,對該模塊的內(nèi)容做了簡要的描述。你應(yīng)為自己 創(chuàng)建的每個模塊都編寫文檔字符串。 下面來創(chuàng)建另一個文件——my_car.py,在其中導(dǎo)入Car類并創(chuàng)建其實例:
my_car.py
1 from car import Car
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()
1處的import語句讓Python打開模塊car,并導(dǎo)入其中的Car類。這樣我們就可以使用Car類了, 就像它是在這個文件中定義的一樣。輸出與我們在前面看到的一樣:
2016 Audi A4
This car has 23 miles on it.
導(dǎo)入類是一種有效的編程方式。如果在這個程序中包含了整個Car類,它該有多長呀!通過 將這個類移到一個模塊中,并導(dǎo)入該模塊,你依然可以使用其所有功能,但主程序文件變得整潔 而易于閱讀了。這還能讓你將大部分邏輯存儲在獨立的文件中;確定類像你希望的那樣工作后, 你就可以不管這些文件,而專注于主程序的高級邏輯了。文章來源:http://www.zghlxwxcb.cn/news/detail-792945.html
關(guān)于“Python”的核心知識點整理大全12-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-792945.html
往期快速傳送門??(在文章最后):
感謝大家的支持!歡迎訂閱收藏!專欄將持續(xù)更新!
到了這里,關(guān)于關(guān)于“Python”的核心知識點整理大全21的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!