繼承進階

先講一個例子:

#老師有生日,怎么組合哪?
class Birthday:  # 生日def __init__(self,year,month,day):self.year = yearself.month = monthself.day = dayclass Teacher:  # 老師<br>def __init__(self,name,birth):self.name = nameself.birthday = birthalex = Teacher('alex','2018-7-14')
print(alex.birthday)# 2018-7-14#但是這么傳日期不好,需要分開,使用組合方式:
class Birthday:def __init__(self,year,month,day):self.year = yearself.month = monthself.day = dayclass Teacher:def __init__(self,name,birth):self.name = nameself.birthday = birthbirth = Birthday(2018,7,14)
alex = Teacher('alex',birth)   # 用實例建立橋梁
print(birth.year)
print(alex.birthday.year)  # 調用組合對象中的屬性# 輸出結果
2018
2018
2018-7-14

Teacher 也可以定義一個方法,執行Birthday類里面的方法:

class Birthday:def __init__(self,year,month,day):self.year = yearself.month = monthself.day = daydef fmt(self):return '%s-%s-%s'%(self.year,self.month,self.day)class Teacher:def __init__(self,name,birth):self.name = nameself.birthday = birthdef birth_month(self):   #算盤打到家了return self.birthday.fmt()  # 引用組合對象的方法
 
birth = Birthday(2018,7,14)
alex = Teacher('alex',birth)
print(birth.year)
print(alex.birthday.year)  # 調用組合對象中的屬性
print(alex.birthday.fmt())  # 調用組合對象中的方法,要加括號
print(alex.birth_month())#運行結果:
2018
2018
2018-7-14
2018-7-14

  總結: 組合就是一個對象引用另一個對象,用它的方法。

繼承的類:父類、基類、超類

想繼承的類:子類、派生類

?


?

講一個繼承的例子:

  貓
  屬性 性別 品種
  方法 吃 喝 爬樹

  狗
  屬性 性別 品種
  方法 吃 喝 看門

從上面可以看出,狗和貓有共同的屬性和方法,唯獨有一個方法是不一樣的。
那么是否可以繼承呢?

class Animal:  # 動物def __init__(self,name,sex,kind):self.name = nameself.sex = sexself.kind = kinddef eat(self):  #print('%s is eating'%self.name)def drink(self):  #print('%s is drinking'%self.name)class Cat(Animal):  #def climb(self):  # 爬樹print('%s is climbing'%self.name)class Dog(Animal):  #def watch_door(self):  # 看門print('%s is watching door'%self.name)tom = Cat('tom','','招財貓')   # 實例化對象
hake = Dog('hake','','藏獒')
print(Cat.__dict__)   # Cat.__dict__ Cat類的命名空間中的所有名字
print(tom.__dict__)   # tom.__dict__ 對象的命名空間中的所有名字
tom.eat()   # 先找自己對象的內存空間 再找類的空間 再找父類的空間
tom.climb()   # 先找自己的內存空間 再找類的空間#運行結果:
{'__doc__': None, 'climb': <function Cat.climb at 0x000001C95178AAE8>, '__module__': '__main__'}
{'sex': '', 'name': 'tom', 'kind': '招財貓'}
tom is eating
tom is climbing

??


?

一、Object類

class A:pass
A()

#實例化的過程

? 1.創建一個空對象
? 2.調用init方法? 其實A是繼承的object,而其初識函數是空的
? 3.將初始化之后的對象返回調用處

  以上代碼,A調用了init方法了?答案是:調用了! 這是什么調用,調用了object類的初始化函數

所有的類都繼承了object類

  查看object的源碼,可以找到__init__方法:

def __init__(self): # known special case of object.__init__""" Initialize self.  See help(type(self)) for accurate signature. """pass既然A繼承了object類,那么它肯定執行了父類object的__init__方法
加一段注釋class A:'''這是一個類'''passa = A()
print(A.__dict__)  # 雙下方法 魔術方法
#運行結果:{'__doc__': '\n 這是一個類\n ', '__module__': '__main__', '__dict__':
<attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__'
of 'A' objects>}

  可以在上面的結果中找到兩個帶object的方法,很明顯這就是調用了object類!

總結:

  任何類實例化都經歷3步,如果類沒有init,由object完成了。


?

 class Parent:passclass Son(Parent):passprint(Son.__bases__)  # (<class '__main__.Parent'>,)class Parent1:pass
class Parent2:passclass Son(Parent1,Parent2):passprint(Son.__bases__)   # (<class '__main__.Parent1'>, <class'__main__.Parent2'>)
__bases__的用法

?

二、單繼承:

  比如人工大戰,人類和狗有共同屬性,比如名字,血量,攻擊了。還有共同的方法吃藥:

class Animal:def __init__(self,name,hp,ad):self.name = name  # 名字self.hp = hp  # 血量self.ad = ad  # 攻擊力def eat(self):print('%s吃藥回血了' % self.name)class Person(Animal):def attack(self,dog):  # 派生類print('%s攻擊了%s' %(self.name,dog.name))class Dog(Animal):def bite(self,person):  # 派生類print('%s咬了%s' %(self.name,person.name))alex = Person('alex',100,10)
print(alex.__dict__)#執行輸出:{'ad': 10, 'hp': 100, 'name': 'alex'}

但是還有不同的,比如人類有性別,狗類有品種怎么么辦哪?可以在子類init里面加屬#Person增加init方法

class Animal:def __init__(self,name,hp,ad):self.name = name  # 名字self.hp = hp  # 血量self.ad = ad  # 攻擊力def eat(self):print('%s吃藥回血了' % self.name)class Person(Animal):def __init__(self,sex):self.sex = sexdef attack(self,dog):  # 派生類print('%s攻擊了%s' %(self.name,dog.name))class Dog(Animal):def __init__(self,kind):self.kind = kinddef bite(self,person):  # 派生類print('%s咬了%s' %(self.name,person.name))
# 人 sex
alex = Person('alex')  # 此時只能傳一個參數,否則報錯
print(alex.__dict__)

#執行輸出: {'sex': 'alex'}

  發現和上面的例子少了一些屬性,animal繼承的屬性都沒有了。what?
因為子類自己有init方法了,它不會執行父類的init方法
那么如何執行父類的init呢?同時保證自己的init方法也能執行?

class Animal:def __init__(self,name,hp,ad):self.name = name  # 名字self.hp = hp  # 血量self.ad = ad  # 攻擊力def eat(self):print('%s吃藥回血了' % self.name)class Person(Animal):def __init__(self,name,hp,ad,sex): Animal.__init__(self,name,hp,ad)  # 執行父類方法 也可以使用super().__init__(name,hp,ad),它不需要self參數,
super(Person,self).__init__(name,hp,ad)
self.sex = sexdef attack(self,dog): # 派生類print('%s攻擊了%s' %(self.name,dog.name))class Dog(Animal):def __init__(self,name,hp,ad,kind):Animal.__init__(self, name, hp, ad)self.kind = kinddef bite(self,person): # 派生類print('%s咬了%s' %(self.name,person.name))# 人 sex alex = Person('alex',100,10,'female') # 實例化 print(alex.__dict__)執行輸出: {'ad': 10, 'name': 'alex', 'hp': 100, 'sex': 'female'}

?

四、多繼承

?

  多繼承和單繼承是一樣的
  如果對象使用名字是子類中有的,那么一定用子類的
  子類沒有,可以到多個父類中去尋找,問題來了,繼承誰的那?

class FlyAnimal:def fly(self):pass
class SwimAnimal:def swim(self):passdef eat():pass
class WalkAnimal:def walk(self):passdef eat():passclass Frog(SwimAnimal,WalkAnimal): pass
class Tiger(SwimAnimal,WalkAnimal):pass
class Swan(FlyAnimal,SwimAnimal,WalkAnimal):pass
class Parrot(FlyAnimal,WalkAnimal):def talk(self):pass
多繼承例子

?

?

?


?

三、super方法

  Animal.__init__(self, name, hp, ad) 是直接使用類名.方法名 這樣執行的。

第二種寫法,使用super:

class Animal:def __init__(self,name,hp,ad):self.name = name  # 名字self.hp = hp  # 血量self.ad = ad  # 攻擊力def eat(self):  # 吃藥print('%s吃藥回血了' % self.name)<br>        self.hp += 20class Person(Animal):def __init__(self,name,hp,ad,sex):#Animal.__init__(self,name,hp,ad)  # 執行父類方法 # super(Person,self).__init__(name,hp,ad)   # 完整寫法.在單繼承中,super負責找到
當前類所在的父類,在這個時候不需要再手動傳selfsuper().__init__(name, hp, ad) # 簡寫.效果同上。它不需要傳參數Person,self。
因為它本來就在類里面,自動獲取參數
self.sex = sexdef attack(self,dog): # 派生類print('%s攻擊了%s' %(self.name,dog.name))class Dog(Animal):def __init__(self,name,hp,ad,kind):super().__init__(name, hp, ad)self.kind = kinddef bite(self,person): # 派生類print('%s咬了%s' %(self.name,person.name))# 人 sex alex = Person('alex',100,10,'female') # 實例化 print(alex.__dict__)#執行輸出: {'ad': 10, 'name': 'alex', 'hp': 100, 'sex': 'female'}類外層調用eat方法: #父類有eat,子類沒有 alex.eat() #找父類 執行輸出: alex吃藥回血了

  比如人吃藥要扣錢,狗吃藥,不要錢。在Animal類中,eat方法,執行時,沒有扣錢。

那么就需要在人類中添加eat方法,定義扣錢動作。

class Animal:def __init__(self,name,hp,ad):self.name = name  # 名字self.hp = hp  # 血量self.ad = ad  # 攻擊力def eat(self):print('%s吃藥回血了' % self.name)class Person(Animal):def __init__(self,name,hp,ad,sex):#Animal.__init__(self,name,hp,ad)  # 執行父類方法# super(Person,self).__init__(name,hp,ad)   # 完整寫法.在單繼承中,super負責找到當前類所在的父類,在這個時候不需要再手動傳selfsuper().__init__(name, hp, ad)  # 簡寫.效果同上。它不需要傳參數Person,self。因為它本來就在類里面,自動獲取參數self.sex = sex  # 性別self.money = 0  # 增加默認屬性moneydef attack(self,dog):  # 派生類print('%s攻擊了%s' %(self.name,dog.name))def eat(self):  # 重新定義eat方法super().eat()  # 執行父類方法eatprint('eating in Person')self.money -= 50  # 扣錢
class Dog(Animal):def __init__(self,name,hp,ad,kind):super().__init__(name, hp, ad)self.kind = kinddef bite(self,person):  # 派生類print('%s咬了%s' %(self.name,person.name))# 人 sex
alex = Person('alex',100,10,'female')   # 實例化
alex.eat()  # 子類有eat 不管父類中有沒有,都執行子類的#執行結果:
# 人 sex
alex = Person('alex',100,10,'female')   # 實例化
alex.eat()  # 子類有eat 不管父類中有沒有,都執行子類的

  # 總結:父類方法,如果子類有個性化需求,可以重新定義次方法。

在類外面

當子類中有,但是想要調父類的。

alex = Person('alex',100,10,'female')   # 實例化
Animal.eat(alex)  # 指名道姓
super(Person,alex).eat()  # 效果同上,super(子類名,子類對象)方法,一般不用#執行輸出:
alex吃藥回血了
alex吃藥回血了 

一般不會在類外面,執行super方法。都是在類里面調用父類方法super是幫助尋找父類的在外部,super沒有簡寫。

?


?

四、鉆石繼承

  父類是新式類,那么子類全是新式類,同理經典類也一樣。在python3里面沒有經典類。

多繼承:

這個形狀,像鉆石一樣,老外喜歡浪漫,有些書籍寫的叫鉆石繼承,代碼如下:

class A:def func(self):print('A')
class B(A):def func(self):print('B')
class C(A):def func(self):print('C')
class D(B,C):def func(self):print('D')d = D()
d.func()#執行輸出:D

#然而,把D的代碼注釋
?
class D(B,C):
  pass
  #def func(self):
    print('D')

#運行結果:B

#把B的代碼注釋:
  class B(A):
    pass
    # def func(self):
        print('B')

#執行輸出: C

#把C的代碼注釋:
  class C(A):
    pass
    # def func(self):
        print('C')

#執行輸出:A

?


?

?廣度優化 :

1.如果從左到右第一個類,
2.在后面的繼承順序中也是第一個,或者不再出現在后面的繼承順序中
3.那么就可以把這個點提取出來,作為繼承順序中的第一個類
廣度優先規則

?

廣度優先搜索算法(英語:Breadth-First-Search,縮寫為BFS),又譯作寬度優先搜索,或橫向優先搜索,是一種圖形搜索算法。簡單的說,

BFS是從根節點開始,沿著樹的寬度遍歷樹的節點。如果所有節點均被訪問,則算法中止。

  也就是第一次不走到頭,頭可能被多個對象繼承,如A,從最后一個引用的類進入A

看圖,查看順序:

?

再看一個龜殼模型:

代碼如下:

class A:def func(self):print('A')
class B(A):passdef func(self):print('B')
class C(A):passdef func(self):print('C')
class D(B):passdef func(self):print('D')
class E(C):passdef func(self):print('E')
class F(D,E):passdef func(self):print('F')f = F()
f.func()

#執行輸出: F

?

看圖,查看順序:

# 在python2中還有深度優先,就是第一次會取到最深處,F->D->B->A->E->C。

在這個例子中,A為頂點,因為有2個類繼承了A

在執行第3步時,由于B繼承了A,B并沒有直接去找A。而是在這這一層中斷查找。

由同層的E去查找,然后到C,最后到A,這就是廣度優先算法

 注意:在廣度優先算法中,Python直接提供了方法mro,可以查看搜索循環:

f = F()
f.func()
print(F.mro())   #需要注意的是super始終是遵循mro的#執行輸出:#通過mro可以查看順序
F
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

?#總結: 新式類 多繼承 尋找名字的順序,遵循廣度優先(mro)!

?經典面試題:

class A:def func(self):print('A')
class B(A):def func(self):super().func()print('B')
class C(A):def func(self):super().func()print('C')
class D(B,C):def func(self):super().func()print('D')d = D()
d.func()#執行結果:   在D(B,C)中先看B中,再看C,從C到A
A
C
B
D

在上的例子中,super不是找父類的,它是找下一個節點的

遇到多繼承和super

? ? 對象.方法

? ? ? ? 找到這個對象對應的類

? ? ? ? 將這個類的所有父類都找到畫成一個圖

? ? ? ? 根據圖寫出廣度優先的順序

? ? ? ? 再看代碼,看代碼的時候,要根據廣度優先順序圖來找對應的super?

    總結:super():

        1、在單繼承中就是單純得尋找父類

        2、在多繼承中就是根據子節點 通過mro循環尋找下一個類


?

深度優化? :只在Python2中,且沒有繼承object,沒有mro和super方法

一條路走到黑
深度優先規則

?

? 所謂深度優化是“一路摸到黑”,也就是說深度優化搜索會不假思索地一直擴展一個狀態直到到達不能被擴展的葉子狀態。

要用到Python2測試,代碼如下:

class A:def func(self):print('A')
class B(A):def func(self):print('B')
class C(A):def func(self):print('C')
class D(B,C):def func(self):print('D')d = D()
d.func()#執行結果: D

在Python2里面,不手動繼承Object,比如class A(object)就是經典類,比如calss A,在例子中B繼承了A,B在去找A,執行輸出A

?

順序如圖: 

?

  深度優化,一條路走到黑,找不到,就回來找其他的

?

?總結:

  經典類:在Python2.*版本才存在,且必須不繼承object

?    1、遍歷的時候遵循深度優化算法

    ? 2、沒有mro() 和 super()方法

  新式類: 在Python2.*版本中,需要繼承object才是新式類

     1、遍歷的時候遵循廣度優先算法

     2、在新式類中,有mro方法,同時也有super方法,但是在2.*版本中,必須傳參數(子類名,子類對象)

?

轉載于:https://www.cnblogs.com/double-W/p/9784799.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253329.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253329.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253329.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PCM接口詳細介紹--TDM方式

1. 概述 PCM = Pulse Code Modulation 是通過等時間隔(即采樣率時鐘周期)采樣將模擬信號數字化的方法。圖為4 bit 采樣深度的PCM數據量化示意圖: PCM數字音頻接口,說明接口傳輸的音頻數據是通過PCM方式采樣得到的,區別于PDM形式;IIS傳輸的也是PCM類型數據,屬于其一個特…

網站同源策略

所謂"同源"指的是"三個相同"&#xff1a;協議&#xff0c;域名&#xff0c;端口。 舉例來說&#xff0c;http://www.example.com/dir/page.html這個網址&#xff0c;協議是http://&#xff0c;域名是www.example.com&#xff0c;端口是80&#xff08;默認端…

Kconfig文件結構(圖文)簡介

1 Kconfig和Makefile 毫不夸張地說&#xff0c;Kconfig和Makefile是我們瀏覽內核代碼時最為依仗的兩個文件。基本上&#xff0c;Linux 內核中每一個目錄下邊都會有一個Kconfig文件和一個Makefile文件。Kconfig和Makefile就好似一個城市的地圖&#xff0c;地圖引導我們去 認識一…

PDM接口介紹

1. 概述 PDM Pulse Density Modulation是一種用數字信號表示模擬信號的調制方法。 PDM則使用遠高于PCM采樣率的時鐘采樣調制模擬分量&#xff0c;只有1位輸出&#xff0c;要么為0&#xff0c;要么為1。因此通過PDM方式表示的數字音頻也被稱為Oversampled 1-bit Audio。相比P…

js正則學習分享

http://www.cnblogs.com/rubylouvre/archive/2010/03/09/1681222.htmlhttp://www.cnblogs.com/tylerdonet/p/4262251.html //正整數 /^[0-9]*[1-9][0-9]*$/; //負整數 /^-[0-9]*[1-9][0-9]*$/; //正浮點數 /^(([0-9]\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9])|([0-9]*[1…

Linux系統下UDP發送和接收廣播消息小例子

分類&#xff1a; 網絡通信 2013-01-07 10:54 1336人閱讀 評論(6) 收藏 舉報 [cpp] view plaincopyprint?// 發送端 #include <iostream> #include <stdio.h> #include <sys/socket.h> #include <unistd.h> #include <sys/types.h>…

Kaggle 泰坦尼克

入門kaggle&#xff0c;開始機器學習應用之旅。 參看一些入門的博客&#xff0c;感覺pandas&#xff0c;sklearn需要熟練掌握&#xff0c;同時也學到了一些很有用的tricks&#xff0c;包括數據分析和機器學習的知識點。下面記錄一些有趣的數據分析方法和一個自己擼的小程序。 1…

語音交互設備 前端信號處理技術和語音交互過程介紹

一、前端信號處理 1. 語音檢測&#xff08;VAD&#xff09; 語音檢測&#xff08;英文一般稱為 Voice Activity Detection&#xff0c;VAD&#xff09;的目標是&#xff0c;準確的檢測出音頻信號的語音段起始位置&#xff0c;從而分離出語音段和非語音段&#xff08;靜音或噪…

css中偽類與偽元素的區別

一&#xff1a;偽類&#xff1a;1:定義&#xff1a;css偽類用于向某些選擇器添加特殊效果。 偽類其實與普通的css類相類似&#xff0c;可以為已有的元素添加樣式&#xff0c;但是他只有處于dom無法描述的狀態下才能為文檔樹中的元素添加樣式&#xff0c;所以將其稱為偽類。 2:偽…

【BZOJ1500】[NOI2005]維修數列 Splay

【BZOJ1500】[NOI2005]維修數列 Description Input 輸入的第1 行包含兩個數N 和M(M ≤20 000)&#xff0c;N 表示初始時數列中數的個數&#xff0c;M表示要進行的操作數目。第2行包含N個數字&#xff0c;描述初始時的數列。以下M行&#xff0c;每行一條命令&#xff0c;格式參見…

bzoj2588: Spoj 10628. Count on a tree(樹上第k大)(主席樹)

每個節點繼承父節點的樹&#xff0c;則答案為query(root[x]root[y]-root[lca(x,y)]-root[fa[lca(x,y)]]) #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> using namespace std; const int maxn1…

圖文詳解YUV420數據格式

YUV格式有兩大類&#xff1a;planar和packed。 對于planar的YUV格式&#xff0c;先連續存儲所有像素點的Y&#xff0c;緊接著存儲所有像素點的U&#xff0c;隨后是所有像素點的V。 對于packed的YUV格式&#xff0c;每個像素點的Y,U,V是連續交*存儲的。 YUV&#xff0c;分為三個…

USB通信接口介紹

1. 概述 Usb Universal Serial Bus全稱通用串行總線&#xff0c;是一種支持熱插拔的高速串行傳輸總線&#xff0c;使用差分信號來傳輸數據。 USB設備可以直接和host通信&#xff0c;或者通過hub和host通信。一個USB系統中僅有一個USB主機&#xff0c;設備包括功能設備和hub&…

關于java中BufferedReader的read()及readLine()方法的使用心得

BufferedReader的readLine()方法是阻塞式的, 如果到達流末尾, 就返回null, 但如果client的socket末經關閉就銷毀, 則會產生IO異常. 正常的方法就是使用socket.close()關閉不需要的socket. 從一個有若干行的文件中依次讀取各行&#xff0c;處理后輸出&#xff0c;如果用以下方法…

HDCVI——一種創新性的高清視頻傳輸方案

什么是HDCVI 2012年11月&#xff0c;大華技術股份有限公司發布了具有自主知識產權的同軸高清傳輸接口技術HDCVI。HDCVI技術是一種基于已有SYV75-3或SYV75-5同軸電纜的高清視頻傳輸方法&#xff0c;能夠在低成本和較低質量的同軸電纜上實現超長距離高清視頻信號的可靠傳輸。相比…

typedef struct 用法

如果在c程序中我們寫&#xff1a;    typedef struct     {    int num;    int age;    }aaa,bbb,ccc;    這算什么呢&#xff1f;    我個人觀察編譯器&#xff08;VC6&#xff09;的理解&#xff0c;這相當于    typedef struct     …

智能機器人品牌簡介

隨著科技的發展&#xff0c;硬件的計算速度和大數據支撐&#xff0c;越來越多的智能化設備和產品出現在我們的面前&#xff0c;為我們的生活帶來更多便利。其中包括智能機器人&#xff0c;這種產品是有自己的“大腦”&#xff0c;可以接收人為指令&#xff0c;為人服務&#xf…

轉 Java對日期Date類進行加減運算一二三

請移步&#xff0c;https://blog.csdn.net/hacker_lees/article/details/74351838 &#xff0c;感謝博主分享轉載于:https://www.cnblogs.com/bestxyl/p/9790088.html

誕生之日 隨筆

今天我誕生了&#xff0c;祝自己誕生日happy&#xff0c;happy&#xff0c;happy&#xff01; 轉載于:https://www.cnblogs.com/xiaohuihui-/p/7594406.html

智能音箱 之 麥克風參數介紹

1. 定義 麥克風&#xff0c;學名為傳聲器&#xff0c;是將聲音信號轉換為電信號的能量轉換器件&#xff1b;聲—電轉換。 與揚聲器正好相反&#xff08;電—聲轉換&#xff09;&#xff0c;構成電聲設備的兩個終端&#xff0c;俗稱咪頭&#xff0c;麥克等。 是電聲系統的入口&a…