面向?qū)ο蟾呒?jí)
一、 特性
特性是指的property.
property這個(gè)詞的翻譯一直都有問題, 很多人把它翻譯為屬性, 其實(shí)是不恰當(dāng)和不準(zhǔn)確的. 在這里翻譯成特性是為了和屬性區(qū)別開來.
屬性是指的attribute, 我們以前學(xué)習(xí)的實(shí)例變量和類變量是attribute, 所以也可以叫做實(shí)例屬性和類屬性.
property(特性)到底是個(gè)什么東西?
我們前面學(xué)習(xí)類屬性和實(shí)例屬性的時(shí)候知道, 訪問他們的時(shí)候就可以直接獲取到這些屬性的值.
而特性可以看成一種特殊的屬性, 為什么呢?
但從訪問方式來看, 特性和屬性看不出來差別, 但是特性實(shí)際上會(huì)經(jīng)過計(jì)算之后再返回值. 所以每一個(gè)特性都始終與一個(gè)方法相關(guān)聯(lián).
1.1 定義特性
定義特性和定義實(shí)例方法類似, 只需要另外在方法上面添加一個(gè)內(nèi)置裝飾器:@property
訪問特性和訪問實(shí)例變量完全一樣, 不需要使用添加括號(hào)去調(diào)用.
import math class Circle: def __init__(self, r): self.r = r @property def
area(self): """ 定義特性 這個(gè)特性是計(jì)算出來圓的面積 :return: """ return math.pi * (self.r ** 2)
c = Circle(10) print(c.area)
很明顯, 特性背后的本質(zhì)是一個(gè)方法的存在, 所以你不可能在外面去修改這個(gè)特性的值!
試圖修改特性的值只會(huì)拋出一個(gè)異常.
c.area = 100
1.2 使用特性的設(shè)計(jì)哲學(xué)
這種特性使用方式遵循所謂的 統(tǒng)一訪問原則.
實(shí)際上, 定義一個(gè)類總是保持接口的統(tǒng)一總是好的.
有了特性, 把訪問屬性和訪問方法統(tǒng)一了, 都像在訪問屬性一樣, 省得去考慮到底什么時(shí)候需要添加括號(hào),什么時(shí)候不用添加括號(hào).
1.3 特性的攔截操作
python 還提供了設(shè)置和刪除屬性.
通過給方法添加其他內(nèi)置裝飾器來實(shí)現(xiàn)
設(shè)置:@特性名.setter
刪除:@特性名.deleter
class Student: def __init__(self, name): self._name = name # name 是特性了,
所以用實(shí)例變量存儲(chǔ)特性的值的是換個(gè)變量名!!! @property def name(self): return self._name
@name.setter def name(self, name): if type(name) is str and len(name) > 2:
self._name = name else: print("你提供的值" + str(name) + "不合法!") @name.deleter def
name(self): print("對(duì)不起, name 不允許刪除") s = Student("李四") print(s.name) s.name =
"彩霞" print(s.name) s.name = "張三" print(s.name) del s.name
二、三大特性之一-封裝性
面向?qū)ο蟮娜筇卣?封裝, 繼承, 多態(tài)
2.1什么是封裝性
1.封裝是面向?qū)ο缶幊痰囊淮筇攸c(diǎn) 2.面向?qū)ο缶幊痰牡谝徊?,就是講屬性和方法封裝到一個(gè)抽象的類中 3.外界使用類創(chuàng)建對(duì)象,然后讓對(duì)象調(diào)用方法
4.對(duì)象方法的細(xì)節(jié)都被封裝在類的內(nèi)部
在類中定義屬性, 定義方法就是在封裝數(shù)據(jù)和代碼.
2.2 私有化屬性
首先先明確一點(diǎn), python 不能真正的對(duì)屬性(和方法)進(jìn)行私有, 因?yàn)?python 沒有想 java 那樣的private可用.
python 提供的"私有", 是為了怕在編程的過程中對(duì)對(duì)象屬性不小心"誤傷"提供的一種保護(hù)機(jī)制! 這種級(jí)別的私有稍微只要知道了規(guī)則,
是很容易訪問到所謂的私有屬性或方法的.
2.2.1 為什么需要私有
封裝和保護(hù)數(shù)據(jù)的需要.
默認(rèn)情況下, 類的所有屬性和方法都是公共的, 也就意味著對(duì)他們的訪問沒有做任何的限制.
意味著, 在基類中定義的所有內(nèi)容都可以都會(huì)被派生類繼承, 并可從派生類內(nèi)部進(jìn)行訪問.
在面向?qū)ο蟮膽?yīng)用程序設(shè)計(jì)中, 我們通常不希望這種行為, 因?yàn)樗麄儽┞痘惖膬?nèi)部實(shí)現(xiàn), 可能導(dǎo)致派生類中的使用的私有名稱與基類中使用的相同的私有名稱發(fā)生沖突.
屬性或方法私有后就可以避免這種問題!
2.2.2 "私有"機(jī)制
為了解決前面說的問題, python 提供了一種叫做名稱改寫(name mangling)的機(jī)制
如果給屬性或者方法命名的時(shí)候, 使用兩個(gè)下劃線開頭(__)的屬性和方法名會(huì)自動(dòng)變形為_類名__方法名, 這樣就避免了在基礎(chǔ)中命名沖突的問題.
class Student: def __init__(self): pass def __say(self): print("我是私有方法你信嗎?") s
= Student() s.__say() # 雙下劃線開頭的方法已經(jīng)被形變, 此處訪問不到
s._Student__say()
2.2.3 不是真正的私有
盡管這種方案隱藏了數(shù)據(jù), 但是并沒有提供嚴(yán)格的機(jī)制來限制對(duì)私有屬性和方法的訪問.
雖然這種機(jī)制好像多了一層處理, 但是這種變形是發(fā)生在類的定義期間, 并不會(huì)在方法執(zhí)行期間發(fā)生, 所以并沒有添加額外的開銷.
2.2.4 不同的聲音
有部分人認(rèn)為這種使用雙__的機(jī)制好辣雞, 寫兩個(gè)下劃線影響效率. 他們使用一個(gè)下劃線, 并把這個(gè)作為一個(gè)約定.
好吧, 你喜歡哪種呢?
三、面向?qū)ο笕筇匦?繼承性(Inheritance)
這一節(jié)我們來學(xué)習(xí)面向的對(duì)象的再一個(gè)特征: 繼承
3.1繼承性的概念
繼承(extends)是創(chuàng)建新類的一種機(jī)制, 目的是專門使用和修改先有類的行為.
原有類稱為超類(super class), 基類(base class)或父類.
新類稱為子類或派生類.
通過繼承創(chuàng)建類時(shí), 所創(chuàng)建的類將繼承其基類所有的屬性和方法, 派生類也可以重新定義任何這些屬性和方法, 并添加自己的新屬性和方法
3.2 繼承性的意義
繼承實(shí)現(xiàn)代碼的重用,相同的代碼不需要重復(fù)的編寫
從子類的角度來看,避免了重復(fù)的代碼。(子類繼承父類后,子類可以直接使用父類的屬性和方法)
從父類的角度來看,子類擴(kuò)展了父類的功能。(因?yàn)樽宇愐彩且粋€(gè)特殊的父類)
* 子類可以直接訪問父類的屬性和方法。
* 子類可以新增自己的屬性和方法。
* 子類可以重寫父類的方法。
3.3 繼承的語法和具體實(shí)現(xiàn)
繼承的語法如下:
class 父類名: pass class 子類名(父類名): pass
3.3.1最簡(jiǎn)單的繼承
python 的繼承是在類名的后面添加括號(hào), 然后在括號(hào)中聲明要繼承的父類.
class Father: def speak(self): print("我是父類中的 speak 方法") # Son繼承 Father 類 class
Son(Father): pass s = Son() s.speak()
說明:
* 從字面上我們看到Son沒有定義任何的方法, 但是由于Son繼承自Father, 則Son會(huì)繼承Father的所有屬性和方法
* 調(diào)用方法時(shí), 方法的查找規(guī)則: 先在當(dāng)前類中查找, 當(dāng)前類找不到想要的方法, 則去父類中查找, 還找不到然后繼續(xù)向上查找. 一旦找到則立即執(zhí)行.
如果找到最頂層還找不到, 則會(huì)拋出異常
示例代碼
# 創(chuàng)建人類 class Person: # 定義吃東西方法 def eat(self): print("吃窩窩頭。。") # 定義睡覺方法 def
sleep(self): print("睡著啦。。") # 創(chuàng)建學(xué)生類 class Student(Person): # 子類新增方法:學(xué)習(xí) def
study(self): print("學(xué)生學(xué)習(xí)啦。。。把你爸樂壞了。。。。。") # 創(chuàng)建父類對(duì)象,訪問父類的方法 zhangsan = Person();
zhangsan.eat() zhangsan.sleep() # 創(chuàng)建子類對(duì)象,訪問父類的方法和子類的方法 ergou = Student();
ergou.eat() # 訪問父類的方法 ergou.sleep() # 訪問父類的方法 ergou.study() # 訪問子類的新增方法
3.3.2 繼承中的__init__()的調(diào)用規(guī)則
如果子類沒有手動(dòng)__init__()方法, 則 python 自動(dòng)調(diào)用子類的__init__()的時(shí)候, 也會(huì)自動(dòng)的調(diào)用基類的__init()__方法.
class Father: def __init__(self): print("基類的 init ") # Son繼承 Father 類 class
Son(Father): def speak(self): pass s = Son()
如果子類手動(dòng)添加了__init__(), 則 python 不會(huì)再自動(dòng)的去調(diào)用基類的__init__()
class Father: def __init__(self): print("基類的 init ") # Son繼承 Father 類 class
Son(Father): def __init__(self): print("子類的 init ") def speak(self): pass s =
Son()
如果想通過基類初始化一些數(shù)據(jù), 則必須顯示的調(diào)用這個(gè)方法, 調(diào)用語法是:
基類名.__init__(self, 參數(shù)...)
class Father: def __init__(self, name): print("基類的 init ") self.name = name
def speak(self): print("我是父類中的 speak 方法" + self.name) # Son繼承 Father 類 class
Son(Father): def __init__(self, name, age): # name 屬性的初始化應(yīng)該交給基類去完成, 手動(dòng)調(diào)用基類的方法.
一般放在首行 Father.__init__(self, name) # 調(diào)動(dòng)指定類的方法, 并手動(dòng)綁定這個(gè)方法的 self print("子類的 init
") self.age = age s = Son("李四", 20) s.speak() print(s.name) print(s.age)
3.4方法的重寫(override)
3.4.1重寫的概念
我們已經(jīng)了解了調(diào)用方法時(shí)候的查找規(guī)則, 先在子類中查找, 子類查找不到再去父類中查找.
如果父類的方法不滿足子類的需求, 利用這個(gè)查找規(guī)則, 我們就可以在子類中添加一個(gè)與父類的一樣的方法, 那么以后就會(huì)直接執(zhí)行子類的方法, 而不會(huì)再去父類中查找.
這就叫方法的覆寫.(override)
>重寫,就是子類將父類已有的方法重新實(shí)現(xiàn)。
父類封裝的方法,不能滿足子類的需求,子類可以重寫父類的方法。在調(diào)用時(shí),調(diào)用的是重寫的方法,而不會(huì)調(diào)用父類封裝的方法。
3.4.2重寫父類方法的兩種情況
*
覆蓋父類的方法
父類的方法實(shí)現(xiàn)和子類的方法實(shí)現(xiàn),完全不同,子類可以重新編寫父類的方法實(shí)現(xiàn)。
具體的實(shí)現(xiàn)方式,就相當(dāng)于在子類中定義了一個(gè)和父類同名的方法并且實(shí)現(xiàn)
*
對(duì)父類方法進(jìn)行擴(kuò)展
子類的方法實(shí)現(xiàn)中包含父類的方法實(shí)現(xiàn)。(也就是說,父類原本封裝的方法實(shí)現(xiàn)是子類方法的一部分)。
在子類中重寫父類的方法
在需要的位置使用super().父類方法來調(diào)用父類的方法
代碼其他的位置針對(duì)子類的需求,編寫子類特有的代碼實(shí)現(xiàn)。
如果在覆寫的方法中, 子類還需要執(zhí)行父類的方法, 則可以手動(dòng)調(diào)用父類的方法:
父類名.方法(self, 參數(shù)...)
class Father: def __init__(self, name): self.name = name def speak(self):
print("我是父類中的 speak 方法" + self.name) # Son繼承 Father 類 class Son(Father): def
__init__(self, name, age): Father.__init__(self, name) self.age = age #
子類中覆寫了父類的方法 def speak(self): Father.speak(self) print("我是子類的 speak 方法" +
self.name + " 年齡:" + str(self.age)) s = Son("李四", 20) s.speak()
3.4.3關(guān)于super
在Python中super是一個(gè)特殊的類(Python 3.x以后出現(xiàn))
super()就是使用super類創(chuàng)建出來的對(duì)象
最常使用的場(chǎng)景就是在重寫父類方法時(shí),調(diào)用在父類中封裝的方法實(shí)現(xiàn)
3.5、父類的私有屬性和方法
* 子類對(duì)象不能在自己的方法內(nèi)部,直接訪問父類的私有屬性或私有方法
* 子類對(duì)象可以通過父類的共有方法間接訪問到私有屬性或私有方法
私有屬性和方法是對(duì)象的隱私,不對(duì)外公開,外界以及子類都不能直接訪問
私有屬性和方法通常用于做一些內(nèi)部的事情
3.6、多繼承
3.6.1多繼承的概念
多繼承:子類可以擁有多個(gè)父類,并且具有所有父類的屬性和方法
? 比如:孩子會(huì)繼承自己的父親和母親的特性
3.6.2多繼承的語法
class 子類名(父類名1, 父類名2...): pass
示例代碼:
# 父類A class A: def test1(self): print("A類中的test1方法。。") # 父類B class B: def
test2(self): print("B類中的test2方法。。") # 子類C同時(shí)繼承A和B class C(A,B): pass # 創(chuàng)建C對(duì)象 c1
= C() c1.test1() c1.test2()
3.6.3多繼承的注意事項(xiàng)
提問:如果不同的父類中存在同名的方法,子類對(duì)象在調(diào)用方法時(shí),會(huì)調(diào)用哪一個(gè)父類中的方法呢?
開發(fā)時(shí),應(yīng)該盡量避免這種容易產(chǎn)生混淆的情況。如果父類之間存在同名的屬性或者方法,應(yīng)該盡量避免使用多繼承
3.6.4 Python中的 MRO (方法搜索順序)[擴(kuò)展]
python中針對(duì)類提供了一個(gè)內(nèi)置屬性,___mro__可以查看方法搜索順序
MRO是method resolution order,主要用于在多繼承時(shí)判斷方法,屬性的調(diào)用路徑
print(C.__mro__)
輸出結(jié)果:
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class
'object'>)
* 在搜索方法時(shí),是按照__mro_-的輸出結(jié)果從左至右的順序查找
* 如果當(dāng)前類中找到方法,就直接執(zhí)行,不再搜索
* 如果沒有找到,就查找下一個(gè)類中是否有對(duì)應(yīng)的方法,如果找到,就直接執(zhí)行,不再搜索
* 如果找到最后一個(gè)雷,還沒有對(duì)應(yīng)的方法,程序報(bào)錯(cuò)
3.6.5 python 中的上帝類型
python 中有個(gè)類比較特殊, 所有的類都直接和間接的繼承自這個(gè)類.
這個(gè)類就是:object. 他是所有類的基類.
如果一個(gè)類沒有顯示的去繼承一個(gè)類, 則這個(gè)類默認(rèn)就繼承object, 也可以去顯示的繼承這個(gè)類.
class Student(object): pass
3.6.6 新式類和舊式(經(jīng)典)類[擴(kuò)展]
object是python為所有對(duì)象提供的基類,提供有一些內(nèi)置的屬性和方法,可以使用
dir函數(shù)查看
新式類:以object為基類的類,推薦使用
經(jīng)典類:不以object為基類的類,不推薦使用
*
在python 3.x中定義類時(shí),如果沒有指定父類,會(huì)默認(rèn)使用object作為該類的父類。所以python 3.x中定義的類都是新式類
*
在python 2.x中定義類時(shí),如果沒有指定父類,則不會(huì)以object作為父類
新式類和經(jīng)典類在多繼承時(shí),會(huì)影響到方法的搜索順序
提示:為了保證編寫的代碼能夠同時(shí)在python 2.x 和python 3.x 運(yùn)行,在定義類的時(shí)候,如果沒有父類,建議統(tǒng)一繼承自object
class 類名(object): pass
四、面向?qū)ο笕筇匦?多態(tài)性(Polymorphism)
4.1多態(tài)性的概念
*
封裝性,根據(jù)職責(zé)將屬性和方法封裝到一個(gè)抽象的類中
? 定義類的準(zhǔn)則
*
繼承性,實(shí)現(xiàn)代碼的重用,相同的代碼不需要重復(fù)的編寫
? 設(shè)計(jì)類的技巧
? 子類針對(duì)自己特有的書需求,編寫特定的代碼
*
多態(tài)性,不同的子類對(duì)象,調(diào)用相同的父類方法,產(chǎn)生不同的執(zhí)行結(jié)果
? 多態(tài)可以增加代碼的靈活性
? 以繼承和重寫父類方法為前提
? 是調(diào)用方法的技巧,不會(huì)影響到類的內(nèi)部設(shè)計(jì)
示例代碼:
""" 多態(tài)性: 繼承和重寫為前提,創(chuàng)建不同的對(duì)象執(zhí)行的具體方法不同 """ class Father(object): def
__init__(self, name): print('父類的init方法') self.name = name def say(self):
print('父類的say方法' + self.name) # Son類繼承于Father類,python中是類繼承于類的 class
Son(Father): def __init__(self, name, age): Father.__init__(self, name)
self.age = age print('子類的init方法') def say(self): Father.say(self)
print('子類的say方法:' + self.name + ',' + str(self.age)) # 以下程序會(huì)體現(xiàn)出多態(tài)性 def
mytest(obj): obj.say() f1 = Father("張爸爸") mytest(f1) print("---------------")
f2 = Son("小頭兒子",5) mytest(f2)
4.2屬性和方法查找順序
多態(tài)性(多態(tài)綁定)是在有繼承背景情況下使用的一種特性.
是指在不考慮實(shí)例背景的情況下使用實(shí)例
多態(tài)的理論根據(jù)是屬性和方法的查找過程. 只要使用obj.attr的方式使用屬性和方法, 則查找順序一定是: 對(duì)象本身, 類定義, 基類定義...
關(guān)于先查找對(duì)象本身的說明: 因?yàn)?python 是一門動(dòng)態(tài)語言, 允許我們?cè)诖a執(zhí)行的過程中去動(dòng)態(tài)的給對(duì)象添加屬性和方法, 所以先從對(duì)象本身查找.
class Father: def __init__(self, name): self.name = name def speak(self):
print("我是父類中的 speak 方法" + self.name) # Son繼承 Father 類 class Son(Father): def
__init__(self, name, age): Father.__init__(self, name) self.age = age def
speak(self): Father.speak(self) print("我是子類的 speak 方法" + self.name + " 年齡:" +
str(self.age)) def foo(): print("我是動(dòng)態(tài)添加上去的...") s = Son("李四", 20) s.speak = foo
s.speak()
4.3 鴨子類型
python 的多態(tài)有的時(shí)候很多人把它稱之為鴨子類型
鴨子類型是指: 看起來像鴨子, 叫起來像鴨子, 走起來像鴨子, 那么它既是鴨子, 你就可以把它當(dāng)鴨子來用.
換成編程語言的說法就是: 對(duì)象屬性和方法的時(shí)候完成時(shí)和類型分開的.
class A: def speak(self): print("a 類中的方法") class B: def speak(self): print("b
類中的方法") def foo(obj): obj.speak() a = A() b = B() foo(a) foo(b)
說明:
* foo接受一個(gè)對(duì)象, 只要這個(gè)對(duì)象中有speak()方法, 就可以正常執(zhí)行, 我們并不關(guān)注他的類型
* A, B這兩個(gè)類沒有任何的關(guān)系, 但是他們都有speak方法, 所以傳遞過去都沒有任何的問題.
* 這就是鴨子模型, 只要你看起來有speak就可以了
五、其他
5.1 特殊屬性__slot__
5.1.1動(dòng)態(tài)添加屬性的問題
通過前面的學(xué)習(xí)中我們知道, 由于 python 的動(dòng)態(tài)語言的特性, 我們可以動(dòng)態(tài)的給對(duì)象添加屬性和方法.
但是這種方式添加的屬性和方法, 只在當(dāng)前對(duì)象上有用, 在其他對(duì)象上是沒用.
class A: pass a1 = A() a1.name = "李四" #給 a1 對(duì)象添加一個(gè)屬性 print(a1.name) a2 = A()
print(a2.name) # a2中沒有 name 屬性, 所以拋異常
5.1.2 __slot__的基本使用
添加屬性和方法最好直接在類中添加, 這樣所有的對(duì)象都可以擁有了.
如果我想避免把某些屬性直接添加到實(shí)例對(duì)象上, 可以使用一個(gè)特殊屬性:__slot__類實(shí)現(xiàn).
給__slot__定義一個(gè)元組, 則元組內(nèi)的屬性名允許在實(shí)例對(duì)象上直接添加, 其他的都不允許.
class A: __slots__ = ("name", ) a1 = A() a1.name = "李四" # 給 a1 對(duì)象添加一個(gè)屬性 name
屬性是允許的 print(a1.name) a1.age = 20 # age 不允許, 所以拋異常 print(a1.age)
注意:
* 我們的__init__()中添加屬性是在self上添加的, 其實(shí)也是直接在對(duì)象上添加, 所以沒有在元組中的屬性名, 也是不允許的.
* 對(duì)于我們直接在類中添加方法是沒有任何的影響的. class A: __slots__ = ("name",) def __init__(self):
self.age = 30 # 也是不允許的 a = A()
5.1.3 繼承中的__slot__
__slot__只對(duì)當(dāng)前類有用, 對(duì)他的子類不起作用. 所以子類也要有自己的__slot__
class A: __slots__ = ("name",) def __init__(self): self.age = 30 # 也是不允許的
class B: def __init__(self): self.age = 30 b = B() print(b.age)
5.1.4 __slot__對(duì)性能上的提升
一些人把__slot__作為一種安全的特性來實(shí)現(xiàn), 然后實(shí)際上他對(duì)內(nèi)存和執(zhí)行速度上的性能優(yōu)化才是最重要的.
不使用__slot__, python 使用字典的方式去存儲(chǔ)實(shí)例數(shù)據(jù)的, 如果一個(gè)程序使用大量的實(shí)例, 測(cè)內(nèi)存占用和執(zhí)行效率都會(huì)影響比較大.
使用__slot__后, python 存儲(chǔ)實(shí)例數(shù)據(jù)的時(shí)候, 不再使用字典, 而是使用一種更加高效的基于數(shù)組的數(shù)據(jù)結(jié)構(gòu). 可以顯著減少內(nèi)存占用和執(zhí)行時(shí)間.
5.2 實(shí)例的測(cè)試類型
任何一個(gè)類都可以做為類型!
創(chuàng)建類的實(shí)例時(shí), 該實(shí)例的類型是這個(gè)類本身, 如果有繼承存在, 則父類型也是這個(gè)實(shí)例的類型.
有些情況下, 我們需要先測(cè)試實(shí)例的類型然后再寫相應(yīng)的代碼.
python 支持 2 種測(cè)試方法:
5.2.1 內(nèi)置函數(shù):type(實(shí)例)
class A: pass class B(A): pass class C: pass a = A() b = B() c = C()
print(type(a)) print(type(b)) print(type(c))
說明:
type返回的是這個(gè)實(shí)例的所屬類的類對(duì)象.
補(bǔ)充一下:
其實(shí)我們經(jīng)常接觸到的有兩種對(duì)象:1. 實(shí)例對(duì)象 2. 類對(duì)象
類對(duì)象就是: 表示類本身的那個(gè)對(duì)象!
5.2.2 內(nèi)置函數(shù):isinstance(實(shí)例, 類型)
class A: pass class B(A): pass class C: pass a = A() b = B() c = C()
print(isinstance(a, A)) # True print(isinstance(b, B)) # True
print(isinstance(b, A)) # True 繼承關(guān)系 print(isinstance(c, C)) # True
print(isinstance(c, A)) # False
說明:
* 這個(gè)函數(shù)返回的是布爾值, 使用起來方便, 所以以后測(cè)試類型建議用這個(gè)函數(shù)
* 這個(gè)函數(shù)繼承關(guān)系也可以測(cè)試出來. b是B類創(chuàng)建出來的, B繼承自A, 所以b也算是類A的實(shí)例.
* 對(duì)一個(gè)實(shí)例也可以同時(shí)測(cè)試多個(gè)類型, 有一個(gè)滿足就返回True, isinstance(實(shí)例, (類 a, 類 b, ...))).
需要把多個(gè)類封裝到一個(gè)tuple中. print(isinstance(c, (A, B, C))) # True
5.2.3 類與類的關(guān)系: issubclass(類1, 類2)
用來測(cè)試類1是不是類2的子類.
class A: pass class B(A): pass class C: pass print(issubclass(B, A)) # True
print(issubclass(C, A)) # False print(issubclass(A, B)) # False
print(issubclass(A, object)) # True print(issubclass(C, (object, A))) # True
第二個(gè)參數(shù)也是可以 class 組成的元組
熱門工具 換一換