1、摘要
面向對象編程 是最有效的軟件編寫方法之一。在面向對象編程中,你編寫表示現實世界中的事物和情景的類,並基於這些類來建立對象。編寫類時,你定義一大類對象都有的通用行爲。基於類建立對象 時,每一個對象都自動具有這種通用行爲,而後可根據須要賦予每一個對象獨特的個性。使用面向對象編程可模擬現實情景,其逼真程度達到了令你驚訝的地步。根據類來建立對象被稱爲實例化 ,這讓你可以使用類的實例。
2、建立和使用類
使用類幾乎能夠模擬任何東西。
下面來編寫一個表示小狗的簡單類Dog ——它表示的不是特定的小狗,而是任何小狗。對於大多數寵物狗,咱們都知道些什麼呢?它們都有名字和年齡;咱們還知道,大多數小狗還會蹲下和打滾。因爲大多數小狗都具有上述兩項信息(名字和年齡)和兩種行爲(蹲下和打滾),咱們的Dog 類將包含它們。這個類讓Python知道如何建立表示小狗的對象。編寫這個類後,咱們將使用它來建立表示特定小狗的實例。
複製代碼
class Dog():
"""一次模擬小狗的簡單嘗試"""
def __init__(self, name, age):
"""初始化屬性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() + " rolled over!")
複製代碼
__init__() 是一個特殊的方法,每當你根據Dog 類建立新實例時,Python都會自動運行它。在這個方法的名稱中,開頭和末尾各有兩個下劃線,這是一種約定,旨在避免Python默認方法與普通方法發生名稱衝突
咱們將方法__init__() 定義成了包含三個形參:self 、name 和age 。在這個方法的定義中,形參self 必不可少,還必須位於其餘形參的前面。爲什麼必須在方法定義中包含形參self 呢?由於Python調用這個__init__() 方法來建立Dog 實例時,將自動傳入實參self 。每一個與類相關聯的方法調用都自動傳遞實參self ,它是一個指向實例自己的引用,讓實例可以訪問類中的屬性和方法。咱們建立Dog 實例時,Python將調用Dog 類的方法__init__()
咱們將經過實參向Dog() 傳遞名字和年齡;self 會自動傳遞,所以咱們不須要傳遞它。每當咱們根據Dog 類建立實例時,都只需給最後兩個形參(name 和age )提供值
處定義的兩個變量都有前綴self 。以self 爲前綴的變量均可供類中的全部方法使用,咱們還能夠經過類的任何實例來訪問這些變量。self.name = name 獲取存儲在形參name 中的值,並將其存儲到變量name 中,而後該變量被關聯到當前建立的實例。self.age = age 的做用與此相似。像這樣可經過實例訪問的變量稱爲屬性
Dog 類還定義了另外兩個方法:sit() 和roll_over(),因爲這些方法不須要額外的信息,如名字或年齡,所以它們只有一個形參self 。咱們後面將建立的實例可以訪問這些方法,換句話說,它們都會蹲下和打滾。當前,sit() 和roll_over() 所作的有限,它們只是打印一條消息,指出小狗正蹲下或打滾。但能夠擴展這些方法以模擬實際狀況:若是這個類包含在一個計算機遊戲中,這些方法將包含建立小狗蹲下和打滾動畫效果的代碼。若是這個類是用於控制機器狗的,這些方法將引導機器狗作出蹲下和打滾的動做
根據類建立實例:
class Dog():
--snip--
my_dog = Dog('willie', 6)
print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")
咱們讓Python建立一條名字爲'willie' 、年齡爲6 的小狗。遇到這行代碼時,Python使用實參'willie' 和6 調用Dog 類中的方法__init__() 。方法__init__() 建立一個表示特定小狗的示例,並使用咱們提供的值來設置屬性name 和age 。方法__init__() 並未顯式地包含return 語句,但Python自動返回一個表示這條小狗的實例。咱們將這個實例存儲在變量my_dog 中。在這裏,命名約定頗有用:咱們一般能夠認爲首字母大寫的名稱(如Dog )指的是類,而小寫的名稱(如my_dog )指的是根據類建立的實例
訪問屬性:
要訪問實例的屬性,可以使用句點表示法,以下代碼來訪問my_dog 的屬性name 的值:
my_dog.name
句點表示法在Python中很經常使用,這種語法演示了Python如何獲悉屬性的值。在這裏,Python先找到實例my_dog ,再查找與這個實例相關聯的屬性name 。在Dog 類中引用這個屬性時,使用的是self.name 。咱們使用一樣的方法來獲取屬性age 的值。在前面的第1條print 語句中,my_dog.name.title() 將my_dog 的屬性name 的值'willie' 改成首字母大寫的;在第2條print 語句中,str(my_dog.age) 將my_dog 的屬性age 的值6 轉換爲字符串。輸出是有關my_dog 的摘要:
My dog's name is Willie.
My dog is 6 years old.
調用方法:
根據Dog 類建立實例後,就可使用句點表示法來調用Dog 類中定義的任何方法
複製代碼
class Dog():
--snip--
my_dog = Dog('willie', 6)
my_dog.sit()
my_dog.roll_over()
複製代碼
要調用方法,可指定實例的名稱(這裏是my_dog )和要調用的方法,並用句點分隔它們。遇到代碼my_dog.sit() 時,Python在類Dog 中查找方法sit() 並運行其代碼。Python以一樣的方式解讀代碼my_dog.roll_over()
Willie is now sitting.
Willie rolled over!
在命名上,若是給屬性和方法指定了合適的描述性名稱,如name 、age 、sit() 和roll_over() ,即使是從未見過的代碼塊,咱們也可以輕鬆地推斷出它是作什麼的
建立多個實例:
複製代碼
class Dog():
--snip--
my_dog = Dog('willie', 6)
your_dog = Dog('lucy', 3)
print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")
my_dog.sit()
print("\nYour dog's name is " + your_dog.name.title() + ".")
print("Your dog is " + str(your_dog.age) + " years old.")
your_dog.sit()
複製代碼
就算咱們給第二條小狗指定一樣的名字和年齡,Python依然會根據Dog 類建立另外一個實例。你可按需求根據一個類建立任意數量的實例,條件是將每一個實例都存儲在不一樣的變量中,或佔用列表或字典的不一樣位置。
3、使用類和實例
你可使用類來模擬現實世界中的不少情景。類編寫好後,你的大部分時間都將花在使用根據類建立的實例上。你須要執行的一個重要任務是修改實例的屬性。你能夠直接修改實例的屬性,也能夠編寫方法以特定的方式進行修改。
複製代碼
class Car():
"""一次模擬汽車的簡單嘗試"""
def __init__(self, make, model, year):
"""初始化描述汽車的屬性"""
self.make = make
self.model = model
self.year = year
def get_descriptive_name(self):
"""返回整潔的描述性信息"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
複製代碼
定義了方法__init__() 。與前面的Dog 類中同樣,這個方法的第一個形參爲self ;咱們還在這個方法中包含了另外三個形參:make 、model 和year 。方法__init__() 接受這些形參的值,並將它們存儲在根據這個類建立的實例的屬性中。建立新的Car 實例時,咱們須要指定其製造商、型號和生產年份
定義了一個名爲get_descriptive_name() 的方法,它使用屬性year 、make 和model 建立一個對汽車進行描述的字符串,讓咱們無需分別打印每一個屬性的值。爲在這個方法中訪問屬性的值,咱們使用了self.make 、self.model 和self.year 。
咱們根據Car 類建立了一個實例,並將其存儲到變量my_new_car中。接下來,咱們調用方法get_descriptive_name() ,指出咱們擁有的是一輛什麼樣的汽車:
2016 Audi A4
給屬性指定默認值:
複製代碼
class Car():
def __init__(self, make,www.michenggw.com model, year):
"""初始化描述汽車的屬性"""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
--snip--
def read_odometer(self):
"""打印一條指出汽車裏程的消息"""
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()
複製代碼
當Python調用方法__init__() 來建立新實例時,將像前一個示例同樣以屬性的方式存儲製造商、型號和生產年份。接下來,Python將建立一個名爲odometer_reading 的屬性,並將其初始值設置爲0。
咱們還定義了一個名爲read_odometer() 的方法,它讓你可以輕鬆地獲悉汽車的里程。一開始汽車的里程爲0:
2016 Audi A4
This car has 0 miles on it.
修改屬性的值:
能夠以三種不一樣的方式修改屬性的值:直接經過實例進行修改;經過方法進行設置;經過方法進行遞增(增長特定的值)
直接修改屬性的值:
複製代碼
class Car():
--snip--
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(www.dasheng178.com)
複製代碼
咱們使用句點表示法來直接訪問並設置汽車的屬性odometer_reading 。這行代碼讓Python在實例my_new_car 中找到屬性odometer_reading ,並將該屬性的值設置爲23:
2016 Audi A4
This car has 23 miles on it.
經過方法修改屬性的值:
若是有替你更新屬性的方法,將大有裨益。這樣,你就無需直接訪問屬性,而可將值傳遞給一個方法,由它在內部進行更新
複製代碼
class Car():
--snip--
def update_odometer(self, mileage):
"""將里程錶讀數設置爲指定的值"""
self.odometer_reading = mileage
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(23)
my_new_car.read_odometer()
複製代碼
添加了方法update_odometer() 。這個方法接受一個里程值,並將其存儲到self.odometer_reading 中。
咱們調用了update_odometer() ,並向它提供了實參23(該實參對應於方法定義中的形參mileage)。它將里程錶讀數設置爲23;而方法read_odometer() 打印該讀數:
2016 Audi A4
This car has 23 miles on it.
再看一個例子:
複製代碼
class Car():
--snip--
def update_odometer(self, mileage):
"""
將里程錶讀數設置爲指定的值
禁止將里程錶讀數往回調
"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
複製代碼
update_odometer() 在修改屬性前檢查指定的讀數是否合理。若是新指定的里程(mileage )大於或等於原來的里程(self.odometer_reading ),就將里程錶讀數改成新指定的里程
不然就發出警告,指出不能將里程錶往回撥
經過方法對屬性的值進行遞增:
複製代碼
class Car():
--snip--
def update_odometer(self, mileage):
--snip--
def increment_odometer(self, miles):
"""將里程錶讀數增長指定的量"""
self.odometer_reading += miles
my_used_car = Car('subaru', 'outback', 2013)
print(my_used_car.get_descriptive_name())
my_used_car.update_odometer(23500)
my_used_car.read_odometer()
my_used_car.increment_odometer(100)
my_used_car.read_odometer()
複製代碼
新增的方法increment_odometer() 接受一個單位爲英里的數字,並將其加入到self.odometer_reading 中。
咱們建立了一輛二手車my_used_car,調用方法update_odometer() 並傳入23500 ,將這輛二手車的里程錶讀數設置爲23 500。
咱們調用increment_odometer()並傳入100 ,以增長從購買到登記期間行駛的100英里:
2013 Subaru Outback
This car has 23500 miles on it.
This car has 23600 miles on it.
你能夠輕鬆地修改這個方法,以禁止增量爲負值,從而防止有人利用它來回撥里程錶。
注意:你可使用相似於上面的方法來控制用戶修改屬性值(如里程錶讀數)的方式,但可以訪問程序的人均可以經過直接訪問屬性來將里程錶修改成任何值。要確保安全,除了進行相似於前面的基本檢查外,還需特別注意細節。
4、繼承
編寫類時,並不是老是要從空白開始。若是你要編寫的類是另外一個現成類的特殊版本,可以使用繼承 。一個類繼承 另外一個類時,它將自動得到另外一個類的全部屬性和方法;原有的類稱爲父類 ,而新類稱爲子類 。子類繼承了其父類的全部屬性和方法,同時還能夠定義本身的屬性和方法。
子類的方法__init__():
複製代碼
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(www.yigouyule2.cn 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):
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
self.odometer_reading += miles
class ElectricCar(Car):
"""電動汽車的獨特之處"""
def __init__(self, make, model, year):
"""初始化父類的屬性"""
super().__init__(make, model, year)
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
複製代碼
首先是Car 類的代碼。建立子類時,父類必須包含在當前文件中,且位於子類前面
定義了子類ElectricCar 。定義子類時,必須在括號內指定父類的名稱。方法__init__() 接受建立Car 實例所需的信息
super() 是一個特殊函數,幫助Python將父類和子類關聯起來。這行代碼讓Python調用ElectricCar 的父類的方法__init__() ,讓ElectricCar 實例包含父類的全部屬性。父類也稱爲超類 (superclass),名稱super所以而得名
爲測試繼承是否可以正確地發揮做用,咱們嘗試建立一輛電動汽車ElectricCar 類的一個實例,但提供的信息與建立普通汽車時相同,並將其存儲在變量my_tesla 中。這行代碼調用ElectricCar 類中定義的方法__init__() ,後者讓Python調用父類Car 中定義的方法__init__() 。咱們提供了實參'tesla' 、'models' 和2016
除方法__init__() 外,電動汽車沒有其餘特有的屬性和方法。當前,咱們只想確認電動汽車具有普通汽車的行爲:
2016 Tesla Model S
給子類定義屬性和方法:
複製代碼
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)
self.battery_size = 70
def describe_battery(self):
"""打印一條描述電瓶容量的消息"""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
my_tesla = ElectricCar(www.078881.cn/'tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
複製代碼
添加了新屬性self.battery_size ,並設置其初始值(如70 )。根據ElectricCar 類建立的全部實例都將包含這個屬性,但全部Car 實例都不包含它。
添加了一個名爲describe_battery() 的方法,它打印有關電瓶的信息。咱們調用這個方法時,將看到一條電動汽車特有的描述:
2016 Tesla Model S
This car has a 70-kWh battery.
對於ElectricCar 類的特殊化程度沒有任何限制。模擬電動汽車時,你能夠根據所需的準確程度添加任意數量的屬性和方法。若是一個屬性或方法是任何汽車都有的,而不是電動汽車特有的,就應將其加入到Car 類而不是ElectricCar 類中。這樣,使用Car 類的人將得到相應的功能,而ElectricCar 類只包含處理電動汽車特有屬性和行爲的代碼
重寫父類的方法:
對於父類的方法,只要它不符合子類模擬的實物的行爲,均可對其進行重寫。爲此,可在子類中定義一個這樣的方法,即它與要重寫的父類方法同名。這樣,Python將不會考慮這個父類方法,而只關注你在子類中定義的相應方法。假設Car 類有一個名爲fill_gas_tank() 的方法,它對全電動汽車來講毫無心義,所以你可能想重寫它。下面演示了一種重寫方式:
def ElectricCar(Car):
--snip--
def fill_gas_tank():
"""電動汽車沒有油箱"""
print("This car doesn't need a gas tank!")
如今,若是有人對電動汽車調用方法fill_gas_tank() ,Python將忽略Car 類中的方法fill_gas_tank() ,轉而運行上述代碼。使用繼承時,可以讓子類保留從父類那裏繼承而來的精華,並剔除不須要的糟粕。
將實例用做屬性:
使用代碼模擬實物時,你可能會發現本身給類添加的細節愈來愈多:屬性和方法清單以及文件都愈來愈長。在這種狀況下,可能須要將類的一部分做爲一個獨立的類提取出來。你能夠將大型類拆分紅多個協同工做的小類。
例如,不斷給ElectricCar 類添加細節時,咱們可能會發現其中包含不少專門針對汽車電瓶的屬性和方法。在這種狀況下,咱們可將這些屬性和方法提取出來,放到另外一個名爲Battery 的類中,並將一個Battery 實例用做ElectricCar 類的一個屬性:
複製代碼
class Car():
--snip--
class Battery():
"""一次模擬電動汽車電瓶的簡單嘗試"""
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.")
class ElectricCar(Car):
"""電動汽車的獨特之處"""
def __init__(self, make, model, year):
"""
初始化父類的屬性,再初始化電動汽車特有的屬性
"""
super().__init__(make, model, year)
self.battery = Battery()
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
複製代碼
定義了一個名爲Battery 的新類,它沒有繼承任何類,__init__() 除self 外,還有另外一個形參battery_size 。這個形參是可選的:若是沒有給它提供值,電瓶容量將被設置爲70。方法describe_battery() 也移到了這個類中
在ElectricCar 類中,咱們添加了一個名爲self.battery 的屬性,這行代碼讓Python建立一個新的Battery 實例(因爲沒有指定尺寸,所以爲默認值70 ),並將該實例存儲在屬性self.battery 中。每當方法__init__() 被調用時,都將執行該操做;所以如今每一個ElectricCar 實例都包含一個自動建立的Battery 實例。
咱們建立一輛電動汽車,並將其存儲在變量my_tesla 中。要描述電瓶時,須要使用電動汽車的屬性battery :
my_tesla.battery.describe_battery()
這行代碼讓Python在實例my_tesla 中查找屬性battery ,並對存儲在該屬性中的Battery 實例調用方法describe_battery()
執行結果爲:
2016 Tesla Model S
This car has a 70-kWh battery.
這看似作了不少額外的工做,但如今咱們想多詳細地描述電瓶均可以,且不會致使ElectricCar 類混亂不堪。下面再給Battery 類添加一個方法,它根據電瓶容量報告汽車的續航里程:
複製代碼
class Car():
--snip--
class Battery():
--snip--
def get_range(self www.feifanyule.cn/):
"""打印一條消息,指出電瓶的續航里程"""
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()
my_tesla.battery.get_range()
複製代碼
新增的方法get_range() 作了一些簡單的分析:若是電瓶的容量爲70kWh,它就將續航里程設置爲240英里;若是容量爲85kWh,就將續航里程設置爲270英里,而後報告這個值。爲使用這個方法,咱們也經過汽車的屬性battery 來調用它
輸出指出了汽車的續航里程(這取決於電瓶的容量):
執行結果爲:
2016 Tesla Model S
This car has a 70-kWh battery.
This car can go approximately 240 miles on a full charge.
模擬較複雜的物件(如電動汽車)時,須要解決一些有趣的問題。續航里程是電瓶的屬性仍是汽車的屬性呢?若是咱們只需描述一輛汽車,那麼將方法get_range() 放在Battery 類中也許是合適的;但若是要描述一家汽車製造商的整個產品線,也許應該將方法get_range() 移到ElectricCar 類中。在這種狀況下,get_range() 依然根據電瓶容量來肯定續航里程,但報告的是一款汽車的續航里程。咱們也能夠這樣作:將方法get_range() 還留在Battery 類中,但向它傳遞一個參數,如car_model ;在這種狀況下,方法get_range() 將根據電瓶容量和汽車型號報告續航里程。這讓你進入了程序員的另外一個境界:解決上述問題時,你從較高的邏輯層面(而不是語法層面)考慮;你考慮的不是Python,而是如何使用代碼來表示實物。到達這種境界後,你常常會發現,現實世界的建模方法並無對錯之分。有些方法的效率更高,但要找出效率最高的表示法,須要通過必定的實踐。只要代碼像你但願的那樣運行,就說明你作得很好!即使你發現本身不得很少次嘗試使用不一樣的方法來重寫類,也沒必要氣餒;要編寫出高效、準確的代碼,都得通過這樣的過程。
5、導入類
隨着你不斷地給類添加功能,文件可能變得很長,即使你妥善地使用了繼承亦如此。爲遵循Python的整體理念,應讓文件儘量整潔。爲在這方面提供幫助,Python容許你將類存儲在模塊中,而後在主程序中導入所需的模塊。
建立car.py文件,並寫入以下代碼:
複製代碼
"""一個可用於表示汽車的類"""
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):
"""
將里程錶讀數設置爲指定的值
拒絕將里程錶往回撥
"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
"""將里程錶讀數增長指定的量"""
self.odometer_reading += miles
複製代碼
文件的開頭,包含了一個模塊級文檔字符串,對該模塊的內容作了簡要的描述。你應爲本身建立的每一個模塊都編寫文檔字符串。
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()
import 語句讓Python打開模塊car ,並導入其中的Car 類。這樣咱們就可使用Car 類了,就像它是在這個文件中定義的同樣。輸出與咱們在前面看到的同樣:
執行結果爲:
2016 Audi A4
This car has 23 miles on it.
雖然同一個模塊中的類之間應存在某種相關性,但可根據須要在一個模塊中存儲任意數量的類。類Battery 和ElectricCar 均可幫助模擬汽車,所以下面將它們都加入模塊car.py中:
複製代碼
"""一組用於表示燃油汽車和電動汽車的類"""
class Car():
--snip--
class Battery():
"""一次模擬電動汽車電瓶的簡單嘗試"""
def __init__(self, battery_size=60):
"""初始化電瓶的屬性"""
self.battery_size = battery_size
def describe_battery(self):
"""打印一條描述電瓶容量的消息"""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
def get_range(self):
"""打印一條描述電瓶續航里程的消息"""
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):
"""模擬電動汽車的獨特之處"""
def __init__(self, make, model, year):
"""
初始化父類的屬性,再初始化電動汽車特有的屬性
"""
super().__init__(make, model, year)
self.battery = Battery()
複製代碼
咱們就能夠import ElectricCar類了
複製代碼
from car import ElectricCar
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
複製代碼
執行結果爲:
2016 Tesla Model S
This car has a 70-kWh battery.
This car can go approximately 240 miles on a full charge.
可根據須要在程序文件中導入任意數量的類。若是咱們要在同一個程序中建立普通汽車和電動汽車,就須要將Car 和ElectricCar 類都導入:
複製代碼
from car import Car, ElectricCar
my_beetle = Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())
my_tesla = ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())
複製代碼
執行結果爲:
2016 Volkswagen Beetle
2016 Tesla Roadster
6、導入整個模塊
你還能夠導入整個模塊,再使用句點表示法訪問須要的類。這種導入方法很簡單,代碼也易於閱讀。因爲建立類實例的代碼都包含模塊名,所以不會與當前文件使用的任何名稱發生衝突。
複製代碼
import car
my_beetle = car.Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())
my_tesla = car.ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())
複製代碼
導入了整個car 模塊。接下來,使用語法 module_name.class_name 訪問須要的類。
導入模塊中的全部類:
from module_name import *
不推薦使用這種導入方式,其緣由有二。首先,若是隻要看一下文件開頭的import 語句,就能清楚地知道程序使用了哪些類,將大有裨益;但這種導入方式沒有明確地指出你使用了模塊中的哪些類。這種導入方式還可能引起名稱方面的困惑。若是你不當心導入了一個與程序文件中其餘東西同名的類,將引起難以診斷的錯誤。這裏之因此介紹這種導入方式,是由於雖然不推薦使用這種方式,但你可能會在別人編寫的代碼中見到它。須要從一個模塊中導入不少類時,最好導入整個模塊,並使用 module_name.class_name 語法來訪問類。這樣作時,雖然文件開頭並無列出用到的全部類,但你清楚地知道在程序的哪些地方使用了導入的模塊;你還避免了導入模塊中的每一個類可能引起的名稱衝突。
在一個模塊中導入另外一個模塊:
有時候,須要將類分散到多個模塊中,以避免模塊太大,或在同一個模塊中存儲不相關的類。將類存儲在多個模塊中時,你可能會發現一個模塊中的類依賴於另外一個模塊中的類。在這種狀況下,可在前一個模塊中導入必要的類。例如,下面將Car 類存儲在一個模塊中,並將ElectricCar 和Battery 類存儲在另外一個模塊中。咱們將第二個模塊命名爲electric_car.py
car.py
複製代碼
"""A class that can be used to represent a car."""
class Car():
"""A simple attempt to represent a car."""
def __init__(self, manufacturer, model, year):
"""Initialize attributes to describe a car."""
self.manufacturer = manufacturer
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""Return a neatly formatted descriptive name."""
long_name = str(self.year) + ' ' + self.manufacturer + ' ' + self.model
return long_name.title()
def read_odometer(self):
"""Print a statement showing the car's mileage."""
print("This car has " + str(self.odometer_reading) + " miles on it.")
def update_odometer(self, mileage):
"""
Set the odometer reading to the given value.
Reject the change if it attempts to roll the odometer back.
"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
"""Add the given amount to the odometer reading."""
self.odometer_reading += miles
複製代碼
electric_car.py
複製代碼
"""A set of classes that can be used to represent electric cars."""
from car import Car
class Battery():
"""A simple attempt to model a battery for an electric car."""
def __init__(self, battery_size=60):
"""Initialize the batteery's attributes."""
self.battery_size = battery_size
def describe_battery(self):
"""Print a statement describing the battery size."""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
def get_range(self):
"""Print a statement about the range this battery provides."""
if self.battery_size == 60:
range = 140
elif self.battery_size == 85:
range = 185
message = "This car can go approximately " + str(range)
message += " miles on a full charge."
print(message)
class ElectricCar(Car):
"""Models aspects of a car, specific to electric vehicles."""
def __init__(self, manufacturer, model, year):
"""
Initialize attributes of the parent class.
Then initialize attributes specific to an electric car.
"""
super().__init__(manufacturer, model, year)
self.battery = Battery()
複製代碼
ElectricCar 類須要訪問其父類Car ,所以咱們直接將Car 類導入該模塊中
複製代碼
from car import Car
from electric_car import ElectricCar
my_beetle = Car('volkswagen', 'beetle', 2015)
print(my_beetle.get_descriptive_name())
my_tesla = ElectricCar('tesla', 'roadster', 2015)
print(my_tesla.get_descriptive_name())
複製代碼
從模塊car 中導入了Car 類,並從模塊electric_car 中導入ElectricCar 類。接下來,咱們建立了一輛普通汽車和一輛電動汽車。這兩種汽車都得以正確地建立:
2016 Volkswagen Beetle
2016 Tesla Roadster
正如你看到的,在組織大型項目的代碼方面,Python提供了不少選項。熟悉全部這些選項很重要,這樣你才能肯定哪一種項目組織方式是最佳的,並能理解別人開發的項目。一開始應讓代碼結構儘量簡單。先儘量在一個文件中完成全部的工做,肯定一切都能正確運行後,再將類移到獨立的模塊中。若是你喜歡模塊和文件的交互方式,可在項目開始時就嘗試將類存儲到模塊中。先找出讓你可以編寫出可行代碼的方式,再嘗試讓代碼更爲組織有序。
7、Python標準庫
Python標準庫 是一組模塊,安裝的Python都包含它。你如今對類的工做原理已有大體的瞭解,能夠開始使用其餘程序員編寫好的模塊了。可以使用標準庫中的任何函數和類,爲此只需在程序開頭包含一條簡單的import 語句。下面來看模塊collections 中的一個類——OrderedDict
字典讓你可以將信息關聯起來,但它們不記錄你添加鍵值對的順序。要建立字典並記錄其中的鍵—值對的添加順序,可以使用模塊collections 中的OrderedDict類。OrderedDict 實例的行爲幾乎與字典相同,區別只在於記錄了鍵值對的添加順序。
複製代碼
from collections import OrderedDict
favorite_languages = OrderedDict()
favorite_languages['jen'] = 'python'
favorite_languages['sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'python'
for name, language in favorite_languages.items():
print(name.title() + "'s favorite language is " +
language.title() + ".")
複製代碼
從模塊collections 中導入了OrderedDict 類而後建立了OrderedDict 類的一個實例,並將其存儲到favorite_languages 中。請注意,這裏沒有使用花括號,而是調用OrderedDict() 來建立一個空的有序字典,並將其存儲在favorite_languages 中
接下來,咱們以每次一對的方式添加名字語言對,而後遍歷favorite_languages ,將以添加的順序獲取調查結果:
Jen's favorite language is Python.
Sarah's favorite language is C.
Edward's favorite language is Ruby.
Phil's favorite language is Python.
這是一個很不錯的類,它兼具列表和字典的主要優勢(在將信息關聯起來的同時保留原來的順序)。等你開始對關心的現實情形建模時,可能會發現有序字典正好可以知足需求。隨着你對標準庫的瞭解愈來愈深刻,將熟悉大量可幫助你處理常見情形的模塊。
8、編碼規範
類名應採用駝峯命名法 ,即將類名中的每一個單詞的首字母都大寫,而不使用下劃線。
實例名和模塊名都採用小寫格式,並在單詞之間加上下劃線。
對於每一個類,都應緊跟在類定義後面包含一個文檔字符串。這種文檔字符串簡要地描述類的功能,並遵循編寫函數的文檔字符串時採用的格式約定。每一個模塊也都應包含一個文檔字符串,對其中的類可用於作什麼進行描述。
可以使用空行來組織代碼,但不要濫用。在類中,可以使用一個空行來分隔方法;而在模塊中,可以使用兩個空行來分隔類。
須要同時導入標準庫中的模塊和你編寫的模塊時,先編寫導入標準庫模塊的import 語句,再添加一個空行,而後編寫導入你本身編寫的模塊的import 語句。在包含多條import 語句的程序中,這種作法讓人更容易明白程序使用的各個模塊都來自何方。python