Python 類中三大關係(依賴 / 組合/ 繼承關係)

来源:https://www.cnblogs.com/xxpythonxx/archive/2020/04/20/12740750.html
-Advertisement-
Play Games

在面向對象的中,類與類之間存在三種關係:依賴關係、組合關係、繼承關係。 1、依賴關係: 將一個類的類名或對象當做參數傳遞給另一個函數被使用的關係就是依賴關係 2、組合關係: 將一個類的對象封裝到另一個類的對象的屬性中,就叫組合 3、繼承關係 (1)什麼是面向對象的繼承 繼承(英語:inheritan ...


在面向對象的中,類與類之間存在三種關係:依賴關係、組合關係、繼承關係。

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • C++的核心理念之一是RAII,Resource Acquisition Is Initialization,資源獲取即初始化。資源有很多種,記憶體、互斥鎖、文件、套接字等;RAII可以用來實現一種與作用域綁定的資源管理方法(如 );這些都不在本文的討論範圍之內。 記憶體是一種資源。從字面上來看,“資源 ...
  • @2020-4-20 作業: 1、編寫遠程執行命令的CS架構軟體 # 服務端 # _*_coding:utf-8_*_ __author__ = 'cc' from socket import * import subprocess ip_port = ('127.0.0.1', 1080) buf ...
  • Java初學者有必要來一張JAVA知識結構圖,首先知道總體有哪些知識分類,進而繼續更細化各個知識。 來一起細品吧! ...
  • 前言 創建型:單例模式,工廠模式,建造者模式,原型模式 結構型:橋接模式,代理模式,裝飾器模式,適配器模式,門面模式,組合模式,享元模式 行為型:觀察者模式,模板模式,策略模式,責任鏈模式,狀態模式,迭代器模式,訪問者模式 介紹 在工作中,我們經常要和Servlet Filter,Spring MV ...
  • 輸入三角形的三邊,判斷是否能構成三角形。若能構成輸出yes,否則輸出no。輸入格式:在一行中直接輸入3個整數,3個整數之間各用一個空格間隔,沒有其他任何附加字元。輸出格式:直接輸出yes或no,沒有其他任何附加字元。代碼如下:#!/usr/bin/python# -*- coding: utf-8 ... ...
  • Java IO流學習總結一:輸入輸出流 轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/54292148本文出自【趙彥軍的博客】 感謝博主,感謝分享 Java流類圖結構: 流的概念和作用: 流是一組有順序的,有起點和終點的位元組集合,是 ...
  • 單例模式(Singleton Pattern)是一種常用的軟體設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當你希望在整個系統中,某個類只能出現一個實例時,單例對象就能派上用場。 比如,某個伺服器程式的配置信息存放在一個文件中,客戶端通過一個 AppConfig 的類來讀取配置文件的信息 ...
  • 1、雙下方法 定義:雙下方法是特殊方法,它是解釋器提供的 由雙下劃線加方法名加雙下劃線 方法名的具有特殊意義的方法,雙下方法主要是python源碼程式員使用的,我們在開發中儘量不要使用雙下方法,但是深入研究雙下方法,更有益於我們閱讀源碼。 (1)調用:不同的雙下方法有不同的觸發方式, __ len_ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...