面向對象編程是最有效的軟件編寫方法之一。根據類來創建對象被稱為實例化,這讓你能夠使用類的實例。
使用類幾乎可以模擬任何東西。
方法 init ():類中的函數稱為方法。與前面學到的有關函數的一切都適用於方法,目前唯一重要的差別是調用方法的方式。在這個方法的名稱中,開頭和末尾各有兩個下劃線,這是一種約定,旨在避免 Python 默認方法與普通方法發生名稱沖突。
編寫一個表示小狗的簡單類 Dog ——它表示的不是特定的小狗,而是任何小狗。
class Dog():
def __init__(self, name, age): #包含三個形參:self 、name 和age
self.name = name #兩個變量都有前綴self
self.age = age
def sit(self): #由於該方法不需要額外的信息,只有一個形參self
print(self.name.title() + " is now sitting.")
def roll_over(self):
print(self.name.title() + " rolled over!")
形參 self 必不可少,還必須位於其他形參的前面。 Python 調用這個 init () 方法來創建 Dog 實例時,將自動傳入實參 self 。每個與類相關聯的方法調用都自動傳遞實參 self ,它是一個指向實例本身的引用,讓實例能夠訪問類中的屬性和方法。
以 self 為前綴的變量都可供類中的所有方法使用,我們還可以通過類的任何實例來訪問這些變量。self.name = name 獲取存儲在形參 name 中的值,並將其存儲到變量 name 中,然後該變量被關聯到當前創建的實例。像這樣可通過實例訪問的變量稱為屬性。
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!")
my_dog = Dog('willie', 6) #實例my_dog
#使用句點表示法訪問實例的屬性my_dog.name
print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")
my_dog.sit() #使用句點表示法來調用Dog類中定義的任何方法
my_dog.roll_over()
類中的每個屬性都必須有初始值,哪怕這個值是 0 或空字符串。在方法 init () 內指定這種初始值是可行的;如果你對某個屬性設置默認值時,就無需包含為它提供初始值的形參。
class Car():
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.record = 0 #設置默認值:裡程數=0
def describe(self): #汽車的特征
name = str(self.year) + ' ' + self.make + ' ' + self.model
return name.title()
def read_record(self): #讀取汽車的裡程表
print("This car has " + str(self.record) + " miles on it!")
my_car = Car('audi','a4','2020')
print("My car: " + my_car.describe())
my_car.read_record()
修改屬性的值有三種不同的方式:直接通過實例進行修改;通過方法進行設置;通過方法進行遞增(增加特定的值)。
直接通過實例修改屬性的值
class Car():
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.record = 0 #設置默認值:裡程數=0
def describe(self): #汽車的特征
name = str(self.year) + ' ' + self.make + ' ' + self.model
return name.title()
def read_record(self): #讀取汽車的裡程表
print("This car has " + str(self.record) + " miles on it!")
my_car = Car('audi','a4','2020')
print("My car: " + my_car.describe())
my_car.record = 100 #直接將裡程數設置為100
my_car.read_record()
通過方法修改屬性的值
class Car():
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.record = 0 #設置默認值:裡程數=0
def describe(self): #汽車的特征
name = str(self.year) + ' ' + self.make + ' ' + self.model
return name.title()
def read_record(self): #讀取汽車的裡程表
print("This car has " + str(self.record) + " miles on it!")
def update_mile(self, mile): #更新裡程數
if mile >= self.record: #檢查數值是否合理
self.record = mile
else:
print("Wrong, the mileage has to be bigger!")
my_car = Car('audi','a4','2020')
print("My car: " + my_car.describe())
my_car.update_mile(100)
my_car.read_record()
通過方法對屬性的值進行遞增
class Car():
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.record = 0 #設置默認值:裡程數=0
def describe(self): #汽車的特征
name = str(self.year) + ' ' + self.make + ' ' + self.model
return name.title()
def read_record(self): #讀取汽車的裡程表
print("This car has " + str(self.record) + " miles on it!")
def update_mile(self, mile): #更新裡程數
if mile >= self.record: #檢查數值是否合理
self.record = mile
else:
print("Wrong, the mileage has to be bigger!")
def increase_mile(self, mile): #增加裡程數
self.record += mile
my_car = Car('audi','a4','2020')
print("My car: " + my_car.describe())
my_car.update_mile(100)
my_car.read_record()
my_car.increase_mile(10) #增加10公裡
my_car.read_record()
編寫類時,並非總是要從空白開始。如果你要編寫的類是另一個現成類的特殊版本,可使用繼承。一個類繼承另一個類時,它將自動獲得另一個類的所有屬性和方法;原有的類稱為父類,而新類稱為子類。子類繼承了其父類的所有屬性和方法,同時還可以定義自己的屬性和方法。
子類的方法 init () 需要父類施以援手。
class Car(): #父類
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.record = 0 #設置默認值:裡程數=0
def describe(self): #汽車的特征
name = str(self.year) + ' ' + self.make + ' ' + self.model
return name.title()
def read_record(self): #讀取汽車的裡程表
print("This car has " + str(self.record) + " miles on it!")
def update_mile(self, mile): #更新裡程數
if mile >= self.record: #檢查數值是否合理
self.record = mile
else:
print("Wrong, the mileage has to be bigger!")
def increase_mile(self, mile): #增加裡程數
self.record += mile
class ElectricCar(Car): #子類:定義子類時,必須在括號內指定父類的名稱
def __init__(self, make, model, year):
super().__init__(make, model, year) #函數super()讓子類實例包含父類的所有屬性
my_electric_car = ElectricCar('yadi','d5','2020')
print("My electric car: " + my_electric_car.describe())
class Car(): #父類
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.record = 0 #設置默認值:裡程數=0
def describe(self): #汽車的特征
name = str(self.year) + ' ' + self.make + ' ' + self.model
return name.title()
def read_record(self): #讀取汽車的裡程表
print("This car has " + str(self.record) + " miles on it!")
def update_mile(self, mile): #更新裡程數
if mile >= self.record: #檢查數值是否合理
self.record = mile
else:
print("Wrong, the mileage has to be bigger!")
def increase_mile(self, mile): #增加裡程數
self.record += mile
class ElectricCar(Car): #子類:定義子類時,必須在括號內指定父類的名稱
def __init__(self, make, model, year):
super().__init__(make, model, year) #函數super()讓子類實例包含父類的所有屬性
self.battery_size = 50 #設置默認值:電瓶容量=50
def describe_battery(self): #電動車容量
print("This electric car has a " + str(self.battery_size) + " KWh battery!")
my_electric_car = ElectricCar('yadi','d5','2020')
print("My electric car: " + my_electric_car.describe())
my_electric_car.describe_battery()
對於父類的方法,只要它不符合子類模擬的實物的行為,都可對其進行重寫。為此,可在子類中定義一個這樣的方法,即它與要重寫的父類方法同名。
#假設父類有一個fill_gas_tank()的方法
class ElectricCar(Car):
def __init__(self, make, model, year):
super().__init__(make, model, year)
def fill_gas_tank(): #重寫
print("The electric car doesn't need a gas tank!") #電動汽車沒有油箱
使用代碼模擬實物時,你可能會發現自己給類添加的細節越來越多:屬性和方法清單以及文件都越來越長。在這種情況下,可能需要將類的一部分作為一個獨立的類提取出來。
class Car(): #父類
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.record = 0 #設置默認值:裡程數=0
def describe(self): #汽車的特征
name = str(self.year) + ' ' + self.make + ' ' + self.model
return name.title()
def read_record(self): #讀取汽車的裡程表
print("This car has " + str(self.record) + " miles on it!")
def update_mile(self, mile): #更新裡程數
if mile >= self.record: #檢查數值是否合理
self.record = mile
else:
print("Wrong, the mileage has to be bigger!")
def increase_mile(self, mile): #增加裡程數
self.record += mile
class ElectricCar(Car): #子類:定義子類時,必須在括號內指定父類的名稱
def __init__(self, make, model, year):
super().__init__(make, model, year) #函數super()讓子類實例包含父類的所有屬性
self.battery = Battery() #添加屬性
def fill_gas_tank():
print("The electric car doesn't need a gas tank!") #電動汽車沒有油箱
#將屬性和方法提取出來放到Battery類中,並將Battery實例用作ElectricCar類的一個屬性
class Battery():
def __init__(self, battery_size=70):
self.battery_size = battery_size
def describe_battery(self): #電動車容量
print("This electric car has a " + str(self.battery_size) + " KWh battery!")
my_electric_car = ElectricCar('yadi','d5','2020')
print("My electric car: " + my_electric_car.describe())
my_electric_car.battery.describe_battery()
隨著你不斷地給類添加功能,文件可能變得很長,即便你妥善地使用了繼承亦如此。為讓文件盡可能整潔可將類存儲在模塊中,然後在主程序中導入所需的模塊。
將 Car 類存儲在一個名為 car.py 的模塊中,然後在 my_car.py 文件中導入 Car 類:
from car import Car
my_car = Car('audi','a4','2020')
print("My car: " + my_car.describe())
my_car.update_mile(100)
my_car.read_record()
雖然同一個模塊中的類之間應存在某種相關性,但可根據需要在一個模塊中存儲任意數量的類。可將 Car 類、Battery 類、ElectricCar 類等存儲在 car.py 的模塊中。
可根據需要在程序文件中導入任意數量的類。
from car import Car, ElectricCar
你還可以導入整個模塊,再使用句點表示法訪問需要的類。
import car
my_car = car.Car('audi','a4','2020')
print("My car: " + my_car.describe())
my_electric_car = car.ElectricCar('yadi','d5','2020')
print("My electric car: " + my_electric_car.describe())
from 模塊名 import *
不推薦使用這種導入方式,其原因有二:
一、這種導入方式沒有明確地指出你使用了模塊中的哪些類。
二、這種導入方式還可能引發名稱方面的困惑。如果你不小心導入了一個與程序文件中其他東西同名的類,將引發難以診斷的錯誤。
將類存儲在多個模塊中時,你可能會發現一個模塊中的類依賴於另一個模塊中的類。在這種情況下,可在前一個模塊中導入必要的類。
例如:將 Car 類存儲在一個模塊中 car.py,並將 ElectricCar 和 Battery 類存儲在另一個模塊中 electric_car.py。ElectricCar 類需要訪問其父類 Car,因此直接將 Car 類導入 electric_car.py 中。
Python 標准庫是一組模塊,安裝的 Python 都包含它,可使用標准庫中的任何函數和類。如,模塊 collections 中的一個類 OrderedDict,OrderedDict 實例記錄了字典中鍵值對的添加順序。