日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

浅谈python使用多态跟不用多态的区别_python 多态和 super 用法

發布時間:2025/3/12 python 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅谈python使用多态跟不用多态的区别_python 多态和 super 用法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

python 中的多態實現非常簡單,只要是在子類中實現和父類同名的方法,便能實現多態,如果想在子類中調用父類的方法,有多種方法,但是當涉及菱形繼承等問題是,super 就成為了比較好的解決方案。

普通繼承

對于比較簡單的繼承關系,通常在子類中有兩種方法來執行父類的方法,示例如下。

基類:

1

2

3class Base(object):

def __init__(self):

print("init Base")

示例 1:

1

2

3

4

5

6

7class A(Base):

def __init__(self):

# 通過父類顯式執行

Base.__init__(self)

print("init A")

a = A()

輸出:

1

2init Base

init A

示例 2:

1

2

3

4

5

6

7class B(Base):

def __init__(self):

# 調用 super

super(B, self).__init__()

print("init B")

b = B()

輸出:

1

2init Base

init B

可以看到,兩種方法都可以調用父類的方法對父類進行初始化。需要注意的是,兩種方法都要傳入 self,但是在子類中調用父類的 super 中傳入的 self是子類對象。

菱形繼承

當有多重繼承,特別是菱形繼承時,這兩種方法就有區別了,示例如下。

示例 1:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20class Base(object):

def __init__(self):

print("init Base")

class A(Base):

def __init__(self):

Base.__init__(self)

print("init A")

class B(Base):

def __init__(self):

Base.__init__(self)

print("init B")

class C(A, B):

def __init__(self):

A.__init__(self)

B.__init__(self)

print("init C")

c = C()

輸出:

1

2

3

4

5init Base

init A

init Base

init B

init C

可以看到,Base 被 init 了兩次,至于其缺陷,在 C++ 中就已經討論過了,反正就是不符合我們的預期,不想這種實現。C++ 中通過虛繼承解決菱形繼承問題,在 python 中可以使用 super 規避這種缺陷。

示例2:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19class Base(object):

def __init__(self):

print("init Base")

class A(Base):

def __init__(self):

super(A, self).__init__()

print("init A")

class B(Base):

def __init__(self):

super(B, self).__init__()

print("init B")

class C(A, B):

def __init__(self):

super(C, self).__init__()

print("init C")

c = C()

輸出

1

2

3

4init Base

init B

init A

init C

運行這個新版本后,你會發現每個 __init__() 方法只會被調用一次了。

為了弄清它的原理,我們需要花點時間解釋下 python 是如何實現繼承的。對于你定義的每一個類,python 會計算出一個所謂的方法解析順序(MRO)列表。 這個 MRO 列表就是一個簡單的所有基類的線性順序表。我們可以看一下 C 的 MRO 表。

1

2>>>C.__mro__

(__main__.C, __main__.A, __main__.B, __main__.Base, object)

為了實現繼承,python 會在 MRO 列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。

而這個 MRO 列表的構造是通過一個 C3 線性化算法來實現的。 我們不去深究這個算法的數學原理,它實際上就是合并所有父類的 MRO 列表并遵循如下三條準則:

子類會先于父類被檢查

多個父類會根據它們在列表中的順序被檢查

如果對下一個類存在兩個合法的選擇,選擇第一個父類

必須牢記:MRO 列表中的類順序會讓你定義的任意類層級關系變得有意義。

當使用 super() 函數時,python 會在 MRO 列表上繼續搜索下一個類(這是一種嵌套實現)。 只要每個重定義的方法統一使用 super() 并只調用它一次, 那么控制流最終會遍歷完整個 MRO 列表,每個方法也只會被調用一次。 這也是為什么在第二個例子中你不會調用兩次 Base.__init__() 的原因。換句話說,super 調用了次且僅有一次所有的父類。

由于 super 遞歸調用的會繼續搜索的特性,可能會出現一些意向不到的效果,比如下面這個例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16class A(object):

def spam(self):

print('A.spam')

super(A, self).spam()

class B(object):

def spam(self):

print('B.spam')

class C(A, B):

pass

c = C()

c.spam()

C.__mro__

輸出

1

2

3A.spam

B.spam

(__main__.C, __main__.A, __main__.B, object)

為啥 c.spam() 會同時調用 A 和 B 的 spam()?其實看到 MRO 順序就明白了:

首先在 c 的類 C 中查找 spam 方法,沒有找到就查找 A 中的 spam 方法。

調用 A 中的 spam 方法,然后遇到 A 的 super 調用,繼續在 MRO 順序表中查找 spam 方法。注意,這里本來調用了 A 的 spam 就應該返回的,但是 super 的存在,導致了繼續遞歸。

遇到 B 的 spam 方法,調用,結束。

super 的使用

對于 python2 和 python3,super 的用法有一些區別:

原因:

python2 沒有默認繼承 object

python3 默認全部繼承 object 類,都是新式類

用法區別:

python2: super(開始類名,self).函數名()

python3:super().函數名()

參考資料

總結

以上是生活随笔為你收集整理的浅谈python使用多态跟不用多态的区别_python 多态和 super 用法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。