在面向物件的中,類與類之間存在三種關系:依賴關系、組合關系、繼承關系,
1、依賴關系:
將一個類的類名或物件當做引數傳遞給另一個函式被使用的關系就是依賴關系
class People:
def __init__(self,name):
self.name = name
def open(self,bx):
bx.open_door(self)
def close(self,bx):
bx.close_door(self)
class Refrigerator:
def __init__(self,name):
self.name = name
def open_door(self,p):
print(f"{p.name} 打開冰箱")
def close_door(self,p):
print(f"{p.name} 關閉冰箱")
r = People("大魔") # People類實體化一個物件r
aux = Refrigerator("奧克斯") # Refrigerator類實體化一個物件aux
r.open(aux) # 將aux物件當做引數傳遞給r物件的open方法使用
r.close(aux) # 將aux物件當做引數傳遞給r物件的close方法使用
2、組合關系:
將一個類的物件封裝到另一個類的物件的屬性中,就叫組合
class Boy:
def __init__(self,name,g):
self.name = name # self = b
self.g = g # g就是girl類實體化的一個物件記憶體地址
def eat(self):
print(f"{self.name}和{self.g.age}歲,且{self.g.weight}公斤的{self.g.name}py朋友.一起吃了個燭光晚餐!")
def make_keep(self):
self.g.live(f"{self.g.weight}公斤的{self.g.name}給{self.name}踩背")
class Girl:
def __init__(self,name,age,sex,weight,*args):
self.name = name
self.age = age
self.sex = sex
self.weight = weight
self.args = args
def live(self,argv):
print(f"直播內容:{argv}")
g = Girl("喬畢得",54,"女",220)
b = Boy("太博",g) # 將物件g當做屬性封裝到b物件的屬性中
b.make_keep()
3、繼承關系
(1)什么是面向物件的繼承
繼承(英語:inheritance)是面向物件軟體技術當中的一個概念,如果一個類別A“繼承自”另一個類別B,就把這個A稱為“B的子類別”,而把B稱為“A的父類別”也可以稱“B是A的超類”,繼承可以使得子類別具有父類別的各種屬性和方法,而不需要再次撰寫相同的代碼,在令子類別繼承父類別的同時,可以重新定義某些屬性,并重寫某些方法,即覆寫父類別的原有屬性和方法,使其獲得與父類別不同的功能,另外,為子類別追加新的屬性和方法也是常見的做法,
? 一般靜態的面向物件編程語言,繼承屬于靜態的,意即在子類別的行為在編譯期就已經決定,無法在執行期擴充,
(2)程式中 A(B)
<1> A -- 子類,派生類
<2> B -- 父類,基類,超類
當我們寫多個類的時候會發現許多問題如:
class Human:
def __init__(self,name,age,sex):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print("吃")
class Dog:
def __init__(self, name, age, sex):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print("吃")
class Cat:
def __init__(self, name, age, sex):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print("吃")
class Pig:
def __init__(self, name, age, sex):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print("吃")
上述代碼重復,這時我們可以簡化相關代碼如:
class Animal: # 父類
"""
動物類
"""
live = "活的"
def __init__(self, name, age, sex):
print("is __init__")
self.name = name
self.sex = sex
self.age = age
def eat(self): # self 是函式的位置引數
print("吃")
class Human(Animal): # 子類
pass
class Dog(Animal): # 子類
pass
class Cat(Animal): # 子類
pass
class Pig(Animal): # 子類
pass
(3)繼承的優點:
-
減少重復代碼
-
結構清晰,規范
-
增加耦合性(耦合性不宜多,在精)
(4)繼承的分類:
<1> 單繼承
<2> 多繼承
Python2: python2.2 之前都是經典類,python2.2之后出現了新式類,繼承object就是新式類
Python3: 只有新式類,不管你繼不繼承object都是新式類
(5)單繼承:
<1> 通過子類的類名使用父類的屬性和方法
'''
遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333
尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書!
'''
class Animal: # 父類
live = "活的"
def __init__(self, name, age, sex):
print("is __init__")
self.name = name
self.sex = sex
self.age = age
def eat(self): # self 是函式的位置引數
print("吃")
class Human(Animal): # 子類
pass
class Dog(Animal): # 子類
pass
Human.eat(12)
Human.__init__(Human,"大魔",18,"男")
print(Human.live)
print(Human.__dict__)
<2> 通過子類的物件使用父類的屬性和方法
class Animal: # 父類
live = "活的"
def __init__(self, name, age, sex):
print("is __init__")
self.name = name
self.sex = sex
self.age = age
def eat(self): # self 是函式的位置引數
print("吃")
class Human(Animal): # 子類
pass
class Dog(Animal): # 子類
pass
p = Human("大魔",18,"男")
d = Dog("remmom",1,'母')
print(d.__dict__)
print(p.__dict__)
p = Human("大魔",18,"男")
print(p.live)
(6)查找順序:
<1> 不可逆(就近原則)
<2> 通過子類,類名使用父類的屬性或方法(查找順序):當前類,當前類的父類,當前類的父類的父類---->
<3> 通過子類物件使用父類的屬性或者方法(查找順序):先找物件,實體化這個物件的類,當前類的父類--->
(7)同時使用子類和父類方法或屬性:
<1> 方法一:不依賴(不需要)繼承
class Animal: # 父類
live = "活的"
def __init__(self, name, age, sex):
# self = p的記憶體地址
self.name = name
self.sex = sex
self.age = age
def eat(self): # self 是函式的位置引數
print("吃")
class Human: # 子類
def __init__(self, name, age, sex, hobby):
# print(Animal.live)
# self = p的記憶體地址
Animal.__init__(self,name,age,sex) # 直接使用Animal類呼叫Animal類中的方法
self.hobby = hobby
class Dog:
def __init__(self, name, age, sex, attitude):
# self = p的記憶體地址
self.name = name
self.sex = sex
self.age = age
self.attitude = attitude # 與Human類進行比較
p = Human("大魔",18,"男","健身")
print(p.__dict__)
<2> 方法二:依賴(需要)繼承
class Animal: # 父類
live = "活的"
def __init__(self, name, age, sex):
# self = p的記憶體地址
self.name = name
self.sex = sex
self.age = age
def eat(self): # self 是函式的位置引數
print("吃")
class Dog(Animal):
def __init__(self, name, age, sex, attitude):
# self = p的記憶體地址
# super(Dog,self).__init__(name,age,sex) # 完整寫法
super().__init__(name,age,sex) # 正常寫法 # 通過super方法使用父類中的方法
self.attitude = attitude
d = Dog("大魔",18,"男","忠誠")
print(d.__dict__)
習題練習:
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()
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()
(8)多繼承
多繼承是繼承多個父類
多繼承中, 存在著這樣?個問題. 當兩個?類中出現了重名?法的時候. 就會涉及到如何查找?類?法的這么?個問題.即MRO(method resolution order) 問題. 在python中這是?個很復雜的問題. 因為在不同的python版本中使?的是不同的演算法來完成MRO的.
(1)經典類:多繼承時從左向右執行
class A:
name = "小寶"
class B(A):
name = "太博"
class C(A):
name = "marry"
class D(B, C):
name = "魔22"
class E:
name = "魔11"
class F(E):
name = "魔"
class G(F, D):
name = "bb"
class H:
name = "aaa"
class Foo(H, G):
pass
f = Foo()
print(f.name)
# 結果為aaa
總結:
經典類:(深度優先)左側優先,一條路走到頭,找不到會回到起點向右查詢
(2)新式類:采用c3演算法 (也有說用廣度優先的 -- 不精確)
# 下述例子在python2.7中運行
class O(object):
name = "小寶"
class D(O):
name = "天魔"
class E(O):
name = "太博"
class F(O):
name = "marry"
class B(D,E):
pass
class C(E,F):
name = "金剛"
class A(B,C):
pass
a = A()
print a.name
# 結果為 天魔
(3)c3 演算法的核心 mro
<1> mro() -- python提供的可以查看多繼承時的執行順序的一種方法
<2> 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演算法的核心,
<3> 表頭和表尾
表頭: 串列的第一個元素
表尾: 串列中表頭以外的元素集合(可以為空)
示例 串列:[A, B, C] 表頭是A,表尾是B和C
<4> 串列之間的+操作
+操作:
[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操作 ......
---------------------
<5> 經典類不能使用mro , 新式類才能使用mro
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/156180.html
標籤:Python
上一篇:Python 運算子匯總
下一篇:Python基礎: 雙下方法
