pyhton基礎【24】面向對象進階五

目錄

十五.多繼承的繼承順序 - mro

調用父類方式不同導致結果不同

單繼承中的super

簡單總結

面試題

十六.魔術方法

魔術方法概述

魔術方法概覽

__getattribute__屬性

__getattribute__注意事項

常用的魔術方法

__doc__

__module__和__class__

__init__

__del__

__call__

__dict__

__getitem__、__setitem__、__delitem__


十五.多繼承的繼承順序 - mro
調用父類方式不同導致結果不同

單獨調用父類的方法

class Parent:def __init__(self, name):print('parent的init開始被調用...')self.name = nameprint('parent的init結束被調用...')class Son1(Parent):def __init__(self, name, age):print('Son1的init開始被調用...')self.age = ageParent.__init__(self, name)print('Son1的init結束被調用...')class Son2(Parent):def __init__(self, name, gender):print('Son2的init開始被調用...')self.gender = genderParent.__init__(self, name)print('Son2的init結束被調用...')class GrandSon(Son1, Son2):def __init__(self, name, age, gender):print('GrandSon的init開始被調用...')Son1.__init__(self, name, age)  # 單獨調用父類的初始化方法Son2.__init__(self, name, gender)print('GrandSon的init結束被調用...')gs = GrandSon('grandson', 12, '男')
print('-' * 30)
print('姓名:', gs.name)
print('年齡:', gs.age)
print('性別:', gs.gender)運行結果:
GrandSon的init開始被調用...
Son1的init開始被調用...
parent的init開始被調用...
parent的init結束被調用...
Son1的init結束被調用...
Son2的init開始被調用...
parent的init開始被調用...
parent的init結束被調用...
Son2的init結束被調用...
GrandSon的init結束被調用...
------------------------------

多繼承中super調用被重寫的父類方法

class Parent:def __init__(self, name, *args, **kwargs):  # 為避免多繼承報錯,使用不定長參數,接受參數print('parent的init開始被調用...')self.name = nameprint('parent的init結束被調用...')class Son1(Parent):def __init__(self, name, age, *args, **kwargs):  # 為避免多繼承報錯,使用不定長參數,接受參數print('Son1的init開始被調用...')self.age = agesuper().__init__(name, *args, **kwargs)  # 為避免多繼承報錯,使用不定長參數,接受參數print('Son1的init結束被調用...')class Son2(Parent):def __init__(self, name, gender, *args, **kwargs):  # 為避免多繼承報錯,使用不定長參數,接受參數print('Son2的init開始被調用...')self.gender = gendersuper().__init__(name, *args, **kwargs)  # 為避免多繼承報錯,使用不定長參數,接受參數print('Son2的init結束被調用...')class GrandSon(Son1, Son2):def __init__(self, name, age, gender):print('GrandSon的init開始被調用...')# 多繼承時,相對于使用類名.__init__方法,要把每個父類全部寫一遍# 而super只用一句話,執行了全部父類的方法,這也是為何多繼承需要全部傳參的一個原因# super(GrandSon, self).__init__(name, age, gender)super().__init__(name, age, gender)print('GrandSon的init結束被調用...')gs = GrandSon('grandson', 12, '男')
print('-' * 30)
print(GrandSon.__mro__)  # 輸出繼承順序
print('姓名:', gs.name)
print('年齡:', gs.age)
print('性別:', gs.gender)運行結果:
GrandSon的init開始被調用...
Son1的init開始被調用...
Son2的init開始被調用...
parent的init開始被調用...
parent的init結束被調用...
Son2的init結束被調用...
Son1的init結束被調用...
GrandSon的init結束被調用...
------------------------------
(<class '__main__.GrandSon'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
姓名: grandson
年齡: 12
性別: 男

上述兩種調用父類的方法是有區別的:

  1. 如果兩個子類中都繼承了父類,當在子類中通過父類名調用時,parent被執行了兩次
  2. 如果兩個子類中都繼承了父類,當在子類中通過super調用時,parent被執行了一次
單繼承中的super
class Parent:def __init__(self, name):print('parent的init開始被調用...')self.name = nameprint('parent的init結束被調用...')class Son(Parent):def __init__(self, name, age):print('Son的init開始被調用...')self.age = agesuper().__init__(name)  # 單繼承不能提供全部參數print('Son的init結束被調用...')class Grandson(Son):def __init__(self, name, age, gender):print('GrandSon的init開始被調用...')self.gender = gendersuper().__init__(name, age)  # 單繼承不能提供全部參數print('GrandSon的init結束被調用...')gs = Grandson('grandson', 12, '男')
print('-' * 30)
print('姓名:', gs.name)
print('年齡:', gs.age)
print('性別:', gs.gender)運行結果:
GrandSon的init開始被調用...
Son的init開始被調用...
parent的init開始被調用...
parent的init結束被調用...
Son的init結束被調用...
GrandSon的init結束被調用...
------------------------------
姓名: grandson
年齡: 12
性別: 男
簡單總結
  1. super().__init__相對于類名.__init__,在單繼承上用法基本無差。
  2. 但在多繼承上有區別,super方法能保證每個父類的方法只會執行一次,而使用類名的方法會導致方法被執行多次,具體看前面的輸出結果。
  3. 多繼承時,使用super方法,對父類的傳參數,由于super的算法導致的原因,必須把參數全部傳遞,否則會報錯。
  4. 單繼承時,使用super方法,則不能全部傳遞,只能傳父類方法所需的參數,否則會報錯。
  5. 多繼承時,相對于使用類名.__init__()方法,要把每個父類全部寫一遍, 而使用super方法,只需寫一句話便執行了全部父類的方法,這也是為何多繼承需要全部傳參的一個原因。
面試題

以下代碼將會輸出什么?

class Parent(object):x = 1class Child1(Parent):passclass Child2(Parent):passprint(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)輸出結果:
1 1 1
1 2 1
3 2 3

使你困惑或是驚奇的是關于最后一行的輸出是3 2 3而不是3 2 1。為什么改變了Parent.x的值還會改變Child2.x的值,但是同時Child1.x值卻沒有改變?

這個答案的關鍵是,在Python中,類變量在內部是作為字典處理的。如果一個變量的名字沒有在當前類的字典中發現,將搜索祖先類(比如父類)直到被引用的變量名被找到(如果這個被引用的變量名既沒有在自己所在的類又沒有在祖先類中找到,會引發一個AttributeError異常 )。

因此,在父類中設置x = 1會使得類變量x在引用該類和其任何子類中的值為1。這就是因為第一個print語句的輸出是1 1 1。

隨后,如果任何它的子類重寫了該值(例如,我們執行語句Child1.x = 2),然后,該值僅僅在子類中被改變。這就是為什么第二個print語句的輸出是1 2 1。

最后,如果該值在父類中被改變(例如,我們執行語句Parent.x = 3),這個改變會影響到任何未重寫該值的子類當中的值(在這個示例中被影響的子類是Child2)。這就是為什么第三個print輸出是3 2 3

十六.魔術方法
魔術方法概述

Python中的魔術方法是一組預定義的方法,它們以雙下劃線開頭和結尾(例如__init__、__str__ 等)。它們有特別的意義,因為Python的解釋器會在某些內置行為發生時自動調用它們。魔術方法允許開發者定義或修改類的默認行為。

Python3中定義的類都是新式類,無論是否寫明一個類繼承object,都會間接或直接繼承object。

class Person(object):pass
In [2]: dir(Person)Out[2]: 
['__class__','__delattr__','__dict__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__','__gt__','__hash__','__init__','__init_subclass__','__le__','__lt__','__module__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__','__weakref__']

Python2默認不繼承object

# Python2中無繼承父類,稱之經典類。Python3中已默認繼承object
class Person:pass
Python 2.7.16 (default, Mar 25 2021, 18:52:10) 
[GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.37.14)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class Person:
...     pass
... 
>>> dir(Person)
['__doc__', '__module__']
>>>
魔術方法概覽

方法名稱

說明

觸發方式

__init__

構造初始化函數

創建實例后賦值時使用,在__new__方法執行后自動調用

__new__

創建類的實例

創建實例時被調用

__class__

實例所在的類的地址

實例.__class__

__str__

返回實例對象的字符串信息

print(類實例)時被觸發。如果沒有沒實現,使用repr返回的結果

__repr__

返回實例對象的字符串信息

print(repr(類實例))被觸發

__del__

析構(對象被刪除前做清理工作)

del實例后,如果對象引用計數為零,則自動調用

__dict__

實例自定義屬性

vars(實例.__dict__)

__doc__

類文檔說明,子類不繼承

help(類或實例)

__getattribute__

屬性訪問攔截器

訪問實例屬性時

__bases__

獲取類所有的直接父類:不能獲取父類的父類

類名.__bases__

__getattribute__屬性

__getattribute__功能很強大:能夠完成屬性訪問時進行攔截

class Student:country = '中國'def __init__(self, name, age, address):self.name = nameself.age = ageself.__address = addressdef info(self):print(self.name, self.age, self.__address, Student.country)  # 使用類對象獲取國家def __info_method(self):print(self.name, self.age, self.__address, self.country)  # 使用實例對象獲取國家def __getattribute__(self, item):  # item傳入的是屬性名而不是屬性值print('開始校驗屬性或方法:', item)return object.__getattribute__(self, item)  # 返回屬性值stu = Student('安娜', 18, '長沙')print('實例對象打印屬性: ', stu.name, stu.age, stu.country)  # 獲取屬性會觸發__getattribute__
print('-' * 30)stu.info()  # 調用實例方法
print('-' * 30)stu._Student__info_method()  # 調用私有方法
print('-' * 30)
print('類對象打印屬性:', Student.country)  # 使用類對象獲取類屬性不會觸發__getattribute__'''
1.直接使用類名.類屬性的形式調用類屬性不會觸發__getattribute__方法
2.如果在當前這個類中調用了方法則__getattribute__會獲取當前這個方法的名稱
'''運行結果:
開始校驗屬性或方法: name
開始校驗屬性或方法: age
開始校驗屬性或方法: country
實例對象打印屬性:  安娜 18 中國
------------------------------
開始校驗屬性或方法: info
開始校驗屬性或方法: name
開始校驗屬性或方法: age
開始校驗屬性或方法: _Student__address
安娜 18 長沙 中國
------------------------------
開始校驗屬性或方法: _Student__info_method
開始校驗屬性或方法: name
開始校驗屬性或方法: age
開始校驗屬性或方法: _Student__address
開始校驗屬性或方法: country
安娜 18 長沙 中國
------------------------------
類對象打印屬性: 中國
__getattribute__注意事項
class Person:def __getattribute__(self, item):print("查詢指定的屬性或方法是否存在...")if item.startswith("h"):return "world"else:return self.set_attribute_method()  # 會出現遞歸調用# try:#     return super().__getattribute__(item)# except AttributeError:#     self.set_attribute_method()@staticmethoddef set_attribute_method():return "模擬設置屬性的方法..."p = Person()# 返回world
print(p.hello)# 會讓程序死掉
# print(p.python)"""
不要在__getattribute__方法中使用self關鍵字只要self關鍵字使用類中的屬性和方法就會觸發__getattribute__
"""
常用的魔術方法
__doc__

表示類的描述信息

class Foo:""" 描述類信息,這是一個類的簡單描述 """def func(self):passprint(Foo.__doc__)
__module__和__class__
  1. __module__表示當前操作的對象在哪個模塊
  2. __class__表示當前操作的對象的類是誰
test.py文件class Person:def __init__(self):self.name = '安娜'
from test import Personobj = Person()
print(obj.__module__)  # 輸出 test 即:輸出模塊
print(obj.__class__)  # 輸出 test.Person 即:輸出類
__init__

構造方法:通過類創建對象時,自動觸發執行

class Person:def __init__(self, name):self.name = nameself.age = 18obj = Person('安娜')  # 自動執行類中的 __init__ 方法
__del__

當對象在內存中被釋放之前,自動觸發執行

注:此方法一般無須定義。因為Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,因為此工作都是交給Python解釋器來執行,所以__del__的調用是由解釋器在進行垃圾回收前自動觸發,執行一些完善工作。

class Foo:def __del__(self):pass
__call__

對象后面加括號,觸發執行

注:__init__方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對于__call__方法的執行是由對象后加括號觸發的,即:對象() 或者 類()()。

class Foo:def __init__(self):passdef __call__(self, *args, **kwargs):print('__call__')obj = Foo()  # 執行 __init__
obj()  # 執行 __call__
__dict__

類或對象中的所有屬性

類的實例屬性屬于對象,類中的類屬性和方法等屬于類。

class Province:country = 'China'def __init__(self, name, count):self.name = nameself.count = countdef func(self, *args, **kwargs):print('func')# 獲取類的屬性,即:類屬性、方法、
print(Province.__dict__)
# 輸出:{'__dict__': <attribute '__dict__' of 'Province' objects>, '__module__': '__main__', 'country': 'China', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Province' objects>, 'func': <function Province.func at 0x101897950>, '__init__': <function Province.__init__ at 0x1018978c8>}obj1 = Province('山東', 10000)
print(obj1.__dict__)
# 獲取 對象obj1 的屬性
# 輸出:{'count': 10000, 'name': '山東'}obj2 = Province('山西', 20000)
print(obj2.__dict__)
# 獲取 對象obj1 的屬性
# 輸出:{'count': 20000, 'name': '山西'}

__str__

如果一個類中定義了__str__方法,那么在打印對象時,默認輸出該方法的返回值

class Foo:def __str__(self):return '雙雙'obj = Foo()
print(obj)
# 輸出:雙雙
__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分別表示獲取、設置、刪除數據

class Foo:def __getitem__(self, key):print('__getitem__', key)def __setitem__(self, key, value):print('__setitem__', key, value)def __delitem__(self, key):print('__delitem__', key)obj = Foo()result = obj['k1']      # 自動觸發執行 __getitem__
obj['k2'] = '安娜'   # 自動觸發執行 __setitem__
del obj['k1']           # 自動觸發執行 __delitem__

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

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

相關文章

如何保障MySQL客戶端連接數據庫安全更安全

公司員工或外協人員&#xff0c;直接使用業務賬號或高權限賬號連接MySQL服務器&#xff0c;如同讓數據在連接時減少風險——賬號密碼易泄露、操作行為難追溯、安全風險陡增&#xff01;尤其是在客戶端連接環節&#xff0c;如何確保每一個接入點都安全可控&#xff0c;每一次操作…

機器學習入門:線性回歸詳解及Scikit-learn API使用指南

一、線性回歸概述線性回歸是統計學和機器學習領域中最基礎、最廣泛應用的預測建模技術之一。自19世紀初由弗朗西斯高爾頓(Francis Galton)首次提出以來&#xff0c;線性回歸已成為數據分析的核心工具&#xff0c;在經濟學、社會科學、生物統計學、工程學等眾多領域發揮著重要作…

高斯牛頓法求解三維變換矩陣的數學推導

目錄一、問題定義二、李代數基礎三、雅可比矩陣推導四、高斯牛頓迭代1. 整體雅可比矩陣2. 正規方程構建3. 參數更新4. 李代數更新五、理論優勢分析一、問題定義 給定兩組三維點云&#xff1a;源點云 P{pi∈R3}i1NP \{p_i \in \mathbb{R}^3\}_{i1}^NP{pi?∈R3}i1N?&#xff0…

JAVA 商城系統為什么受歡迎?ZKmall開源商城靈活定制 + 插件接入適配市場

在電商系統開發這塊&#xff0c;技術選得好不好&#xff0c;直接關系到平臺穩不穩定、能不能擴展、適配能力強不強。JAVA 語言因為 “跨平臺性突出、安全性高、可擴展性好” 這些特點&#xff0c;成了企業級電商系統的首選技術。而 ZKmall 商城基于 JAVA 開發的商城系統&#x…

【數據結構之哈夫曼樹與編碼實現】

文章目錄 前言一、哈夫曼樹與哈夫曼編碼簡介1. 什么是哈夫曼樹&#xff1f;2. 為什么需要哈夫曼編碼&#xff1f; 二、哈夫曼編碼原理三、哈夫曼樹的構建步驟詳解1. 統計字符頻率2. 定義哈夫曼樹節點3. 最小堆&#xff08;優先隊列&#xff09;的構造4. 合并節點&#xff0c;構…

基于Hadoop的京東廚具商品數據分析及商品價格預測系統的設計與實現

文章目錄有需要本項目的代碼或文檔以及全部資源&#xff0c;或者部署調試可以私信博主項目介紹數據采集用戶界面系統展示管理員界面每文一語有需要本項目的代碼或文檔以及全部資源&#xff0c;或者部署調試可以私信博主 項目介紹 本項目圍繞“京東廚具數據分析系統的設計與實…

深入解析TCP:可靠傳輸的核心機制與實現邏輯(三次握手、四次揮手、流量控制、滑動窗口、擁塞控制、慢啟動、延時應答、面向字節流、粘包問題)

Linux系列 文章目錄 Linux系列一、TCP連接的建立與斷開1.1 TCP 三次握手1.2 TCP四次揮手1. TCP連接的本質是應用層間的通信通道2. 斷開連接的核心是終止應用層通信3. 常見誤解澄清 二、TCP協議的機制2.1 流量控制2.2 滑動窗口2.2.1 滑動窗口的工作原理2.2.2 基于滑動窗口快重傳…

基于開源AI智能客服、AI智能名片與S2B2C商城小程序的微商服務質量提升路徑研究

摘要&#xff1a;在科技飛速發展的背景下&#xff0c;產品技術含量與復雜度顯著提升&#xff0c;客戶正確使用產品并體驗其價值愈發依賴代理的專業指導與服務。本文聚焦開源AI智能客服、AI智能名片與S2B2C商城小程序在微商服務中的應用&#xff0c;通過分析其技術原理與實踐案例…

[netty5: HttpHeaders HttpHeadersFactory]-源碼分析

HttpHeaders HttpHeaders 是用于存儲和操作HTTP請求或響應頭部字段的接口。 // DefaultHttpHeaders, HttpHeadersFactory.TrailingHttpHeaders public interface HttpHeaders extends Iterable<Entry<CharSequence, CharSequence>> {static HttpHeaders emptyHead…

基于Flink 1.20、StarRocks與TiCDC構建高效數據處理鏈路教程

在大數據處理領域&#xff0c;實現高效、實時的數據處理與分析至關重要。Flink作為強大的流批一體化計算框架&#xff0c;結合StarRocks這一高性能的實時分析型數據庫&#xff0c;再搭配TiCDC&#xff08;TiDB Change Data Capture&#xff09;用于捕獲數據變更&#xff0c;能夠…

便捷的Office批量轉PDF工具

軟件介紹 本文介紹的軟件是一款能實現Office批量轉換的工具&#xff0c;名為五五Excel word批量轉PDF。 軟件小巧 這款五五Excel word批量轉PDF軟件大小不到2M。 操作步驟一 使用該軟件時&#xff0c;只需把軟件和需要轉換的Word或Excel文件放在同一個文件夾里。 操作步驟…

tcp長連接與短連接

TCP連接本身是一個傳輸層協議&#xff0c;它既可以實現長連接&#xff0c;也可以實現短連接。這取決于應用層的使用方式。 短連接&#xff08;Short Connection&#xff09; 特點&#xff1a;每次請求都建立新的TCP連接&#xff0c;完成后立即關閉流程&#xff1a;建立連接 →…

llvm polly,親自測試

1&#xff09;下載并安裝 Polly - Getting Started git clone https://github.com/llvm/llvm-project.git 大概需要半個小時&#xff0c;有時候被墻掉就打不開 2&#xff09; mkdir build && cd build cmake -DLLVM_ENABLE_PROJECTSclang;polly ../llvm cmake --b…

Spring AI 項目實戰(十四):Spring Boot + Vue3 +AI + DeepSeek 實現空氣質量智能預測系統(附完整源碼)

系列文章 序號文章名稱1Spring AI 項目實戰(一):Spring AI 核心模塊入門2Spring AI 項目實戰(二):Spring Boot + AI + DeepSeek 深度實戰(附完整源碼)3Spring AI 項目實戰(三):Spring Boot + AI + DeepSeek 打造智能客服系統(附完整源碼)4

騰訊云 CDN 不支持 WebSocket 的現狀與華為云 CDN 的替代方案-優雅草卓伊凡

騰訊云 CDN 不支持 WebSocket 的現狀與華為云 CDN 的替代方案-優雅草卓伊凡 問題背景 卓伊凡今天發現&#xff0c;騰訊云 CDN 不支持 WebSocket 協議&#xff0c;而公司的部分業務&#xff08;如實時聊天、在線協作、游戲互動、股票行情推送等&#xff09;依賴長連接通信。昨…

MybatisPlus(一)擴展功能

擴展功能 一、靜態工具二、邏輯刪除三、通用枚舉1、定義枚舉2、配置枚舉處理器3、測試 四、JSON類型處理器1、定義實體2、使用類型處理器 五、分頁1、配置分頁插件2、分頁API3、示例 一、靜態工具 有的時候Service之間也會相互調用&#xff0c;為了避免出現循環依賴問題&#…

Redis哨兵模式之Sentinel模式(二)

一、多節點哨兵如何配置&#xff1f; 哨兵配置原理圖 注意&#xff1a;sentinel哨兵模式的搭建是建立在redis主從復制節點配置基礎而搭建&#xff0c;在主從配置中從庫需要配置好replicaof關聯上主庫并關閉安全模式&#xff0c;然后設置好bind端口才能關聯上機器&#xff0c;而…

基于Excel的數據分析思維與分析方法

數據分析一定要會Excel、SQL和Python&#xff1f;非常肯定地回答您&#xff0c;Python、R語言、Excel函數和VBA&#xff0c;以及高級數據分析軟件&#xff0c;都學不到&#xff0c;您將學到&#xff1a;5個有效的數據分析利器&#xff0c;以及分析思維 一、描述性統計分析 在…

計算機網絡筆記(不全)

一、計算機網絡體系結構1.計算機網絡的概念計算機網絡&#xff1a;由若干結點和連接這些結點的鏈路組成。結點可以是計算機、集線器、交換機、路由器等。互連網(internet)&#xff1a;多個計算機網絡通過路由器互相連接而成&#xff0c;可用任意協議通信。互聯網(因特網Interne…

XML Schema 復合元素

XML Schema 復合元素 引言 XML(可擴展標記語言)作為一種靈活的標記語言,廣泛應用于數據交換和存儲。XML Schema 是一種用于描述和定義 XML 文檔結構的語言,它定義了 XML 文檔的元素、屬性、類型和約束。本文將詳細介紹 XML Schema 中的復合元素,并探討其在實際應用中的重…