天天看點

什麼是繼承python_面向對象繼承

Python 面向對象繼承

一 什麼是面向對象的繼承

比較官方的說法就是:

繼承(英語:inheritance)是面向對象軟體技術當中的一個概念。如果一個類别A“繼承自”另一個類别B,就把這個A稱為“B的子類别”,而把B稱為“A的父類别”也可以稱“B是A的超類”。繼承可以使得子類别具有父類别的各種屬性和方法,而不需要再次編寫相同的代碼。在令子類别繼承父類别的同時,可以重新定義某些屬性,并重寫某些方法,即覆寫父類别的原有屬性和方法,使其獲得與父類别不同的功能。另外,為子類别追加新的屬性和方法也是常見的做法。 一般靜态的面向對象程式設計語言,繼承屬于靜态的,意即在子類别的行為在編譯期就已經決定,無法在執行期擴充。

字面意思就是:子承父業,合法繼承家産,就是如果你是獨生子,而且你也很孝順,不出意外,你會繼承你父母所有家産,他們的所有财産都會由你使用(敗家子兒除外)。

那麼用一個例子來看一下繼承:

class Person:

def __init__(self,name,sex,age):

self.name = name

self.age = age

self.sex = sex

class Cat:

def __init__(self,name,sex,age):

self.name = name

self.age = age

self.sex = sex

class Dog:

def __init__(self,name,sex,age):

self.name = name

self.age = age

self.sex = sex

# 繼承的用法:

class Aniaml(object):

def __init__(self,name,sex,age):

self.name = name

self.age = age

self.sex = sex

class Person(Aniaml):

pass

class Cat(Aniaml):

pass

class Dog(Aniaml):

pass

繼承的有點也是顯而易見的:

1,增加了類的耦合性(耦合性不宜多,宜精)。

2,減少了重複代碼。

3,使得代碼更加規範化,合理化。

二 繼承的分類

就向上面的例子:

Aminal 叫做父類,基類,超類。 Person Cat Dog: 子類,派生類。 繼承:可以分單繼承,多繼承。

這裡需要補充一下python中類的種類(繼承需要):

在python2x版本中存在兩種類.:   ⼀個叫經典類. 在python2.2之前. ⼀直使⽤的是經典類. 經典類在基類的根如果什麼都不寫.   ⼀個叫新式類. 在python2.2之後出現了新式類. 新式類的特點是基類的根是object類。 python3x版本中隻有一種類: python3中使⽤的都是新式類. 如果基類誰都不繼承. 那這個類會預設繼承 object

三 單繼承

3.1 類名,對象執行父類方法

class Aniaml(object):

type_name = '動物類'

def __init__(self,name,sex,age):

self.name = name

self.age = age

self.sex = sex

def eat(self):

print(self)

print('吃東西')

class Person(Aniaml):

pass

class Cat(Aniaml):

pass

class Dog(Aniaml):

pass

# 類名:

print(Person.type_name) # 可以調用父類的屬性,方法。

Person.eat(111)

print(Person.type_name)

# 對象:

# 執行個體化對象

p1 = Person('春哥','男',18)

print(p1.__dict__)

# 對象執行類的父類的屬性,方法。

print(p1.type_name)

p1.type_name = '666'

print(p1)

p1.eat()

3.2 執行順序

class Aniaml(object):

type_name = '動物類'

def __init__(self,name,sex,age):

self.name = name

self.age = age

self.sex = sex

def eat(self):

print(self)

print('吃東西')

class Person(Aniaml):

def eat(self):

print('%s 吃飯'%self.name)

class Cat(Aniaml):

pass

class Dog(Aniaml):

pass

p1 = Person('barry','男',18)

# 執行個體化對象時必須執行__init__方法,類中沒有,從父類找,父類沒有,從object類中找。

p1.eat()

# 先要執行自己類中的eat方法,自己類沒有才能執行父類中的方法。

3.3 同時執行類以及父類方法

方法一:

如果想執行父類的func方法,這個方法并且子類中夜用,那麼就在子類的方法中寫上:

父類.func(對象,其他參數)

舉例說明:

class Aniaml(object):

type_name = '動物類'

def __init__(self,name,sex,age):

self.name = name

self.age = age

self.sex = sex

def eat(self):

print('吃東西')

class Person(Aniaml):

def __init__(self,name,sex,age,mind):

'''

self = p1

name = '春哥'

sex = 'laddboy'

age = 18

mind = '有思想'

'''

# Aniaml.__init__(self,name,sex,age) # 方法一

self.mind = mind

def eat(self):

super().eat()

print('%s 吃飯'%self.name)

class Cat(Aniaml):

pass

class Dog(Aniaml):

pass

# 方法一: Aniaml.__init__(self,name,sex,age)

# p1 = Person('春哥','laddboy',18,'有思想')

# print(p1.__dict__)

# 對于方法一如果不了解:

# def func(self):

# print(self)

# self = 3

# func(self)

方法二:

利用super,super().func(參數)

class Aniaml(object):

type_name = '動物類'

def __init__(self,name,sex,age):

self.name = name

self.age = age

self.sex = sex

def eat(self):

print('吃東西')

class Person(Aniaml):

def __init__(self,name,sex,age,mind):

'''

self = p1

name = '春哥'

sex = 'laddboy'

age = 18

mind = '有思想'

'''

# super(Person,self).__init__(name,sex,age) # 方法二

super().__init__(name,sex,age) # 方法二

self.mind = mind

def eat(self):

super().eat()

print('%s 吃飯'%self.name)

class Cat(Aniaml):

pass

class Dog(Aniaml):

pass

# p1 = Person('春哥','laddboy',18,'有思想')

# print(p1.__dict__)

單繼承的課堂練習

# 1

class Base:

def __init__(self, num):

self.num = num

def func1(self):

print(self.num)

class Foo(Base):

pass

obj = Foo(123)

obj.func1() # 123 運⾏的是Base中的func1

# 2

class Base:

def __init__(self, num):

self.num = num

def func1(self):

print(self.num)

class Foo(Base):

def func1(self):

print("Foo. func1", self.num)

obj = Foo(123)

obj.func1() # Foo. func1 123 運⾏的是Foo中的func1

# 3

class Base:

def __init__(self, num):

self.num = num

def func1(self):

print(self.num)

class Foo(Base):

def func1(self):

print("Foo. func1", self.num)

obj = Foo(123)

obj.func1() # Foo. func1 123 運⾏的是Foo中的func1

# 4

class Base:

def __init__(self, num):

self.num = num

def func1(self):

print(self.num)

self.func2()

def func2(self):

print("Base.func2")

class Foo(Base):

def func2(self):

print("Foo.func2")

obj = Foo(123)

obj.func1() # 123 Foo.func2 func1是Base中的 func2是⼦類中的

# 再來

class Base:

def __init__(self, num):

self.num = num

def func1(self):

print(self.num)

self.func2()

def func2(self):

print(111, self.num)

class Foo(Base):

def func2(self):

print(222, self.num)

lst = [Base(1), Base(2), Foo(3)]

for obj in lst:

obj.func2() # 111 1 | 111 2 | 222 3

# 再來

class Base:

def __init__(self, num):

self.num = num

def func1(self):

print(self.num)

self.func2()

def func2(self):

print(111, self.num)

class Foo(Base):

def func2(self):

print(222, self.num)

lst = [Base(1), Base(2), Foo(3)]

for obj in lst:

obj.func1() # 那筆來吧. 好好算

四 多繼承

class ShenXian: # 神仙

def fei(self):

print("神仙都會⻜")

class Monkey: # 猴

def chitao(self):

print("猴⼦喜歡吃桃⼦")

class SunWukong(ShenXian, Monkey): # 孫悟空是神仙, 同時也是⼀隻猴

pass

sxz = SunWukong() # 孫悟空

sxz.chitao() # 會吃桃⼦

sxz.fei() # 會⻜

此時, 孫悟空是⼀隻猴⼦, 同時也是⼀個神仙. 那孫悟空繼承了這兩個類. 孫悟空⾃然就可以執⾏這兩個類中的⽅法. 多繼承⽤起來簡單. 也很好了解. 但是多繼承中, 存在着這樣⼀個問題. 當兩個⽗類中出現了重名⽅法的時候. 這時該怎麼辦呢? 這時就涉及到如何查找⽗類⽅法的這麼⼀個問題.即MRO(method resolution order) 問題. 在python中這是⼀個很複雜的問題. 因為在不同的python版本中使⽤的是不同的算法來完成MRO的.

4.1經典類的多繼承

雖然在python3中已經不存在經典類了. 但是經典類的MRO最好還是學⼀學. 這是⼀種樹形結構周遊的⼀個最直接的案例. 在python的繼承體系中. 我們可以把類與類繼承關系化成⼀個樹形結構的圖. 來, 上代碼:

class A:

pass

class B(A):

pass

class C(A):

pass

class D(B, C):

pass

class E:

pass

class F(D, E):

pass

class G(F, D):

pass

class H:

pass

class Foo(H, G):

pass

對付這種mro畫圖就可以:

什麼是繼承python_面向對象繼承

繼承關系圖已經有了. 那如何進⾏查找呢? 記住⼀個原則. 在經典類中采⽤的是深度優先,周遊⽅案. 什麼是深度優先. 就是⼀條路走到頭. 然後再回來. 繼續找下⼀個.

什麼是繼承python_面向對象繼承

圖中每個圈都是準備要送雞蛋的住址. 箭頭和⿊線表⽰線路. 那送雞蛋的順序告訴你入⼝在最下⾯R. 并且必須從左往右送. 那怎麼送呢?

什麼是繼承python_面向對象繼承

如圖. 肯定是按照123456這樣的順序來送. 那這樣的順序就叫深度優先周遊. ⽽如果是142356呢? 這種被稱為⼴度優先周遊. 好了. 深度優先就說這麼多. 那麼上⾯那個圖怎麼找的呢? MRO是什麼呢? 很簡單. 記住. 從頭開始. 從左往右. ⼀條路跑到頭, 然後回頭. 繼續⼀條路跑到頭. 就是經典類的MRO算法.

類的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C. 你猜對了麼?

4.2 新式類的多繼承

4.2.1 mro序列

class A:

pass

class B(A):

pass

class C(A):

pass

class D(B, C):

pass

class E:

pass

class F(D, E):

pass

class G(F, D):

pass

class H:

pass

class Foo(H, G):

pass

print(Foo.mro())

4.2.2 C3算法(不講,自己了解)

MRO是一個有序清單L,在類被建立時就計算出來。 通用計算公式為:

mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )

(其中Child繼承自Base1, Base2)

如果繼承至一個基類:class B(A) 這時B的mro序列為

mro( B ) = mro( B(A) )

= [B] + merge( mro(A) + [A] )

= [B] + merge( [A] + [A] )

= [B,A]

如果繼承至多個基類:class B(A1, A2, A3 …) 這時B的mro序列

mro(B) = mro( B(A1, A2, A3 …) )

= [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )

= ...

計算結果為清單,清單中至少有一個元素即類自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。

4.2.2. 表頭和表尾

表頭:   清單的第一個元素

表尾:   清單中表頭以外的元素集合(可以為空)

示例   清單:[A, B, C]   表頭是A,表尾是B和C

4.2.3. 清單之間的+操作

+操作:

[A] + [B] = [A, B] (以下的計算中預設省略) ---------------------

merge操作示例:

如計算merge( [E,O], [C,E,F,O], [C] )

有三個清單 : ① ② ③

1 merge不為空,取出第一個清單清單①的表頭E,進行判斷

各個清單的表尾分别是[O], [E,F,O],E在這些表尾的集合中,因而跳過目前目前清單

2 取出清單②的表頭C,進行判斷

C不在各個清單的集合中,因而将C拿出到merge外,并從所有表頭删除

merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )

3 進行下一次新的merge操作 ......

---------------------

什麼是繼承python_面向對象繼承

計算mro(A)方式:

mro(A) = mro( A(B,C) )

原式= [A] + merge( mro(B),mro(C),[B,C] )

mro(B) = mro( B(D,E) )

= [B] + merge( mro(D), mro(E), [D,E] ) # 多繼承

= [B] + merge( [D,O] , [E,O] , [D,E] ) # 單繼承mro(D(O))=[D,O]

= [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D

= [B,D,E] + merge([O] , [O])

= [B,D,E,O]

mro(C) = mro( C(E,F) )

= [C] + merge( mro(E), mro(F), [E,F] )

= [C] + merge( [E,O] , [F,O] , [E,F] )

= [C,E] + merge( [O] , [F,O] , [F] ) # 跳過O,拿出并删除

= [C,E,F] + merge([O] , [O])

= [C,E,F,O]

原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])

= [A,B] + merge( [D,E,O], [C,E,F,O], [C])

= [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳過E

= [A,B,D,C] + merge([E,O], [E,F,O])

= [A,B,D,C,E] + merge([O], [F,O]) # 跳過O

= [A,B,D,C,E,F] + merge([O], [O])

= [A,B,D,C,E,F,O]

---------------------

結果OK. 那既然python提供了. 為什麼我們還要如此⿇煩的計算MRO呢? 因為筆 試.......你在筆試的時候, 是沒有電腦的. 是以這個算法要知道. 并且簡單的計算要會. 真是項⽬ 開發的時候很少有⼈這麼去寫代碼.

這個說完了. 那C3到底怎麼看更容易呢? 其實很簡單. C3是把我們多個類産⽣的共同繼 承留到最後去找. 是以. 我們也可以從圖上來看到相關的規律. 這個要⼤家⾃⼰多寫多畫圖就 能感覺到了. 但是如果沒有所謂的共同繼承關系. 那⼏乎就當成是深度周遊就可以了