python day 17 繼承(inheritance) 和 派生(derived) 、 多型 polymorphic 、 封裝 enclosure 、 內建函式 過載
目錄:
繼承(inheritance) 和 派生(derived) 、 多型 polymorphic 、 封裝 enclosure 、 內建函式 過載
issubclass 函式
語法:
issubclass(cls, class_or_tuple) 判斷一個類是否是繼承自其它的類,如果此類cls 是class 或tuple中的一個派生子類,則返回True, 否則返回False
示例:
class A:
pass
class B(A):
pass
class C(B):
pass
class D(B):
pass
issubclass(B , A) # True
issubclass(C, B) # True
issubclass(D, C) # False
issubclass(C, (int, str)) False
封裝 enclosure
作用:
- 封裝是指隱藏類的實現細節.讓使用者不關心這些細節;
- 封裝的目的是讓使用者通過儘可能少的使用例項變數名(屬性)操作物件
私有屬性和方法
- 語法:
- python類中以雙下劃線(‘__’)開頭,不以雙下劃線結尾的識別符號為私有成員
- 私有成員只能被方法呼叫,不能在子類或其它地方使用
私有成員有兩種:
- 私有屬性
- 私有方法
示例:
class A:
多型 polymorphic
字面意思:多種狀態
多型是指在有繼承/派生關係的類中,呼叫基類物件的方法,實際能呼叫子類的覆蓋方法的現象叫多型
多型說明:
多型呼叫方法與物件相關,不與類相關
python的全部物件只有”執行時狀態(動態)”, 沒有”C++/Java”裡的”編譯時狀態(靜態)”
多型示例:
class Shape:
def draw(self):
pass
class Point(Shape):
def draw(self):
print("正在畫一個點")
class Circle(Point):
def draw(self):
print("正在畫一個圓")
def my_draw(s):
s.draw() # 呼叫哪兒方法呢? 在執行時動態決定呼叫的方法
s1 = Circle()
s2 = Point()
my_draw(s1)
my_draw(s2)
面向物件程式語言的特徵:
- 封裝
- 繼承
- 多型
面向物件的語言: C++/Java/Python/Swift/C#
多繼承 multiple inheritance
定義:
多繼承是指一個子類繼承自兩個或兩個以上的基類
語法:
class 類名(超類名1, 超類名2, ...):
pass
示例:
# 此示例示意多繼承
class Car:
def run(self, speed):
print("汽車以", speed, "km/h的速度行駛")
class Plane:
def fly(self, height):
print("飛機以海拔", height, "米的高度飛行")
class PlaneCar(Car, Plane):
"""飛行汽車類, 時繼承 自Car和 Plane"""
p1 = PlaneCar()
p1.fly(10000)
p1.run(299)
多繼承的問題(缺陷)
- 識別符號(名字空間)衝突的問題
要謹慎使用多繼承 - 示例:
# 小張寫了一個類A
class A:
def m(self):
print("A.m()被呼叫")
# 小李寫了一個類B:
class B:
def m(self):
print("B.m() 被呼叫")
# 小王感覺小張和小李寫的兩個類自己可以用
class AB(A, B):
pass
ab = AB()
ab.m() # 請問呼叫誰?
多繼承的 MRO (Method Resolution Order)問題
MRO 方法搜尋順序問題
python 3 廣度優先
python 2 深度優先
函式重寫 overwrite
什麼是函式重寫
在自定義的類中,通過新增特定的方法,讓自定義的類生成的物件(例項) 能象內建物件一樣進行內建函式操作
物件轉字串函式重寫
repr(obj) 返回一個能代表此物件的字串,通常:
eval(repr(obj)) == obj
str(obj) 通過給定的物件返回一個字串(這個字串通常是給人閱讀的)
換句話說:
repr(obj) 返回的字串是給python用的
str(obj) 返回字串是給人看的
重寫方法
repr(obj) 函式的重寫方法 def repr(self)
str(obj) 函式的重寫方法 def str(self)
當物件沒有 str方法時,則返回repr(self)的值
內建函式重寫
obj.abs() 方法對應 abs(obj)
obj.len() 方法對應 len(obj)
obj.reversed() 方法對應 reversed(obj)
obj.round() 方法對應 round(obj)
示例見:
# 此示例示意abs(obj) 函式的重寫方法 obj.__abs__() 方法的使用
class MyInteger:
def __init__(self, value):
self.data = value
def __repr__(self):
return 'MyInteger(%d)' % self.data
def __abs__(self):
if self.data < 0:
return MyInteger(-self.data) # 建立一個新的以物件並返回
return MyInteger(self.data)
def __len__(self):
'''len(x)函式規定只能返回整數值,
因此此方法不能返回字串等其它型別的值'''
return 100
I1 = MyInteger(-10)
print(I1) # <-- 此處等同於print(str(I1))
I2 = abs(I1) # I2 = MyInteger(10)
print(I2) # MyInteger(10)
print(len(I1)) # I1.__len__()
數值轉換函式重寫
obj.complex() 對應 complex(obj)
obj.int() 對應 int(obj)
obj.float() 對應 float(obj)
obj.bool() 對應 bool(obj)
布林測試函式的重寫
- 格式:
def bool(self):
… - 作用:
- 用於bool(obj)函式取值
- 用於if語句真值表達式中
- 用於while語句真值表達式中
- 說明:
布測試式方法的查詢順序是 bool方法,其次是len方法
如果沒有以上方法則返回True
示例見:
04_bool.py
迭代器(高階)
什麼是迭代器
可以通過 next(obj) 函式取值的物件,就是迭代器
迭代器協議:
迭代器議是指物件能夠使用next函式獲取下一項資料,在沒有下一項資料時觸發一個StopIteration異常來終止迭代的約定
迭代器協議的實現方法:
- 要求:
在類內需要定義 next(self)方法來實現迭代器協議 語法形式:
class MyIterator: def __next__(self): 迭代器協議 return 資料
什麼是可迭代物件
是指能用iter(obj)函式返回迭代器的物件(例項)
可迭代物件的內部要定義 iter(self)方法來返回迭代器物件
練習:
- 完善學生管理系統讀取學生資訊的功能
看懂類的封裝的用意,及功能的劃分(如:save_to_file(self)方法等)
寫一個實現迭代器協議的類 Primes 讓此類可以生成從b開始的n個不素數
class Primes:
def init(self, b, n):
….
….
for x in Primes(10, 4):
print(x) # 11 13 17 194.擴充套件學生資訊管理程式,試想能否在不改變原Student類的基礎上,為每個學生新增一個家庭住址的資訊
(提示,用繼承/派生機制建立一個新的類)- 11) 新增修改家庭住址的功能