當前位置:首頁 » 編程語言 » pythonmro

pythonmro

發布時間: 2023-05-01 12:32:36

1. python可以多繼承嗎

Python支持多繼承,與C++一樣都會出現一種問題:子類繼承的多個父類又繼承了同一個父類,這時就有可能會出現父類構造方法被調用多次的情況。關於這個問題,我找了一些資料,雖然沒有親自全部驗證,這里我總結一下自己對這個問題的看法。

Python和C++的關於這個問題的解決方案不太一樣,當然Python還要看它的版本。

C++用的方案是引入了虛繼承的語法避免同一個類被構造了多次。

Python用的方法是MRO(method resolution order,方法解析順序) 。在在Python2.3之前,MRO的實現是基於DFS的,而在Python2.3以後MRO的實現是基於C3演算法。找到的資料解釋了一下更換演算法的原因:

為什麼採用C3演算法

C3演算法最早被提出是用於Lisp的,應用在Python中是為了解決原來基於深度優先搜索演算法不滿足本地優先順序,和單調性的問題。

本地優先順序:指聲明時父類的順序,比如C(A,B),如果訪問C類對象屬性時,應該根據聲明順序,優先查找A類,然後再查找B類。

單調性:如果在C的解析順序中,A排在B的前面,那麼在C的所有子類里,也必須滿足這個順序。

------------------------------新式類和舊式類中查找屬性的順序不同-------------------------------------

在新式類中,查找一個要調用的函數或者屬性的時候,是廣度優先搜搜的。

在舊式類當中,是深度優先搜索的。

2. python的類和對象中的super函數的問題

問題一
因為在B類中調用了super方法,所以沒有執行完B類就去執行C類的程序
super方法在多重繼承程序中的調用順序,採用的是C3演算法(在python3中)。
C3演算法的規則如下

①.從底層開始,選擇入邊為零的點。

②.從左到右。

③深度探索。但受限於②規則。

每一個類都可以用mro函數查看自己的繼承順序(MRO全稱Method Resolution Order,就是用來定義繼承方法的調用順序)

對於你的程序

分析

①規則。得到D類,去掉D類以後,入邊為零的是B類和C類

②規則。選擇B類,去掉B類後,入邊為零的只有C類。結論是D–>B–>C–>A。

在d=D()語句前加print(D.mro()),就可以列印出D類的繼承順序

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
問題二
python3的繼承不同於普通的繼承,super函數已經考慮到了重復繼承的問題,所以對於A類只訪問一次

3. Python入門精華-OOP調用父類的方法及MRO方法解析序列

在繼承關系中,我們想調用已經被覆蓋了的父類的方法,就需要如下實現:

解決方法:

要調用父類中的方法,就要使用超類(超集)方法super(),該方法旨在調用已經被覆蓋的父類的成員方法。

討論:

有關python是如何實現繼承的?

針對每一個定義的類,都會計算出一個成為方法解析順序(MRO)的元組,其只是簡單的對所有基類進行簡單地線性排列。

通過上述的C類調用MRO表,我們不難看出,它將本類開始一直到object類直接所有的父類一次性從左向右逐層向上的排列了出來(先排列自己,在排列自己的父類,最後排列父類的父類,以及最後的object)

然而MRO為何如此排列,這里要涉及到一個非常令人討厭的數學演算法,C3線性化處理,這里只是總結其三個約束:(簡單點說,其實就是對父類進行歸並排列)

1、先檢查子類,再檢查父類

2、有多個父類時,按照MRO表的順序依次查看

3、如果下一個待選的類出現了兩個合法的選擇,那察銷悶么就從第一個父類中選取。

4、補充一點:MRO對類的排序幾乎適用於任何定義的類層次結構。

來了來了,它真的來了:重點~~

有很多同學是否仔細看過上邊的代碼?

有關super()函數,以下重點需要各位明白:

在重寫的方法中僅使用一次super()方法時,會按照MRO表從下一個類開始搜索對應的方法或屬性,以此類推。 所以C中重寫了父類的構造,構造中有super,所以會按照順序去查找MRO中下一個類的方法,發現A中敗彎也有super,就會再去B中找對應的方法(同名方法是__init__),所以找到B的構造,可是B中又有super,就會再去MRO中B的下一個類(Base)中找對應的方法(Base的__init__()方法),所以會先列印「Base.__init__」,列印完後又因為B的__init__中還有列印「B.__init__」,所以接著列印『B.__init__』,又因為列印完後A中還有列印「A.__init__」,所以再列印「A.__init__」,最後列印「C.__init__」。這樣就可以遍歷MRO整張表中所有的對應的__init__()方法,並且讓每個方法只會被調用一次。

為了更好的記憶:當所有重寫的方法中只使用了一次super函數時,會從最上層的類依次調用其指定的方法即可以理解為(object->Base->B->A->C)。

所以,輸出結果為:

甚至於如下情況更為耐人尋味,仔細品一斗哪品:

值的一提的是:AB均沒有顯式的繼承的父類,為何結果為列印『AB』呢?這里就要理解MRO的含義了哦!

4. python 多重繼承,繼承的幾個父類都需要傳遞參數,怎麼在子類計算出父類傳遞的參數總和呢

運行你的代碼:出錯位置: c = C()

出錯結果:TypeError: __init__() missing 1 required positional argument: ' num1 '

先來看你的程序__main()__部分:a = A(2) 和 b = B(5) 這是類A和類B的一個實例。在python中實例變數是用於每個實例的唯一數據,這就說明你這里的傳遞參數2或者是5隻能用在實例化的 a 或者是 b 下才有作用。 那麼重點看c = C( ) ,c是類對象C的實例化,c 只能用自身實例變數才有用,因此前面的實例 a 下的變數 num1=2 和 實例 b 下的變數 num1=5對實例c是無用的。所以,出錯結果很明顯了缺少傳遞的位置參數了。這為什麼提示缺少1個位置參數呢?下面為你簡單講解一下吧。你也可以用內置方法__mro__() :查看方法或者屬性的調用路徑——print(類名.__mro__)

類C是多繼承類A和類B的,多繼承(不存在super()重寫方法下),類C的實例化c是怎麼工作的——對於實例c調用方法或屬性過程是這樣的:查找當前類C中是否存在,然後在多個父類中按照從左往右順序查找(類A中先查找,類B中後查找),只要在這個過程中找到就退出了,後面的就不再查找了。

好吧,給你分析一下你程序的過程:類A和類B中都有__init__()同一個方法,方法相同那首先就查找唄——先查找類C(沒有對__init__()進行修改,那就是跳過了),然後再去類A查找,好嘛這就找到了__init__(self, num1),找到了就退出了。所以這樣一看對類C進行實例化就需要傳遞一個參數給num1就夠了。你也可以交換繼承位置class C(B, A),這樣就是類C實例化需要傳遞一個參數給num2就夠了。這樣過程就清晰了。

好第三個問題來了:你類C中有兩個參數呀num1和num2,而實例化又僅需要一個參數就夠了,這樣就肯定會產生問題了。

不信你試試給c = C(2)產生錯誤:AttributeError: 'C' object has no attribute 'num2'

解決方法1:既然沒有屬性num2就在類C中刪掉就是了,然後c = C(2)就可以運行成功了。

解決方案2:類變數用於類的所有實例共享的屬性和方法。因此,要想共用這兩個變數num1和num2,就得讓搜索的時候不要進到類A和類B中前提下,將它們變成對應的類變數就可以了。第一個前提很好實現:在類C下 定義:def __init__(self) : pass 第二個條件也比較好實現:將類A或類B的 __init__(self, num) : X.num = num X為對應的類名。(說明:self表示類實例化對象,即self.num 表示實例變數;X表示類對象,則X.num表示類變數),這樣就可以共享類A和類B的變數了。

classA:
def__init__(self,num1):
A.num1=num1


classB:
def__init__(self,num2):
B.num2=num2


classC(A,B):

def__init__(self):
pass

defnum_sum(self):
returnself.num2+self.num1


if__name__=='__main__':
a=A(2)
b=B(5)
c=C()
print(c.num_sum())

5. python列名稱有中文括弧怎麼讀取

一、萌新語法
輸入和輸出
print()

#列印括弧的內容

#第一種:不帶引號,讓計算機讀懂括弧里的內容,列印最終的結果

>>>print(1+1)

#第二種:帶單引號,計算機無須理解,原樣復述引號中的內容

>>>print('秋水共長天一色')

秋水共長天一色

#第三種:帶雙引號,作用和單引號一樣;當列印內容中有單引號時,可以使用雙引號

>>>print("Let's go")

Let's go

>>> print('Let's go')

Let's go

#也可以使用轉義字元+單引號(')來實現單引號

#第四種:帶三引號,實現換行

>>>print('''python小課

最好的python課程''')
pyton小課

最好的python課程

# 採用轉義字元"n"也可以換行

input()

#收集信息

>>>name = input('請輸入你的forchange ID:')

# 使用變數賦值來獲取輸入的信息

變數的命名
1.只能是一個詞;

2.只能包含字母、數字鬧飢和下劃線;

3.不能以數字開頭;

4.盡量描述包含的數據內容;

5.不要使用python函數名和關鍵字。

>>>number = 34

>>>name = 'forchange'

>>>list_class = ['基礎語法課程','爬蟲分析初階','爬蟲分析進階','自動化辦公']

#以上number,name,list_class都是是變數名

條件判斷
條件判斷的解釋:讓計算機知道,在什麼條件下,該去做什麼。

單向判斷
if…

#如果條件成立,就執行語句

>>>number = 6

>>>if number > 3:

... pirnt(number)

6

#注意格式!if後面要加冒號,同時執行語句要縮進四個空格。(空格和tab,我選空格?^^)

雙向判斷
if…else…

#條件成立執行if語句,否則執行else語句

number = 7

if number < 3:

pirnt(number)

else:

number = number - 3

print(number)

#結果輸出為4

#if和else是同一層級,不需要縮進。if和else下的執行語句都需要縮進四個空格。

if…else…和if…if…的區別

#if…else…一個條件滿足後就不會進行其他判斷(if代表的條件和else代表的條件是互斥的)

#if…if…會遍歷所有條件,一個條件無論滿足還是不滿足,都會進行下一個條件的判斷

多向判斷
if…elif…else

#三個及其以上條件的判斷

grade = 65

if 80 <= grade <=100:

print('成績優秀')

elif 60 <= grade < 80:

print('成績中等')

else :

print('成績差')

#結果輸出為成績中等

IF嵌套
if 嵌套

#使用if進行條件判斷,還希望在條件成立的執行語句中再增加條件判斷,即if中還有if,這兩個if非平級

grade = 15

if 80 <= grade <=100:

print('成績優秀')

elif 60 <= grade < 80:

print('成績中等')

else :

print('成績差')

if 20<= grade <60:

print('再努力一把,還有救!')

else :

print('你要比以前更努力才行,你可以的!')

#結果輸出為:

成績差

你要比以前更努力才行,你可以的!

#注意,嵌套的第二個if縮進了4個空格,表示不同的層級。

二、數據類型
數據類型
python常見的數據類型:字元串,整數型,浮點數,列表,字典,布爾值,元組。

最基本的數據類型有三種:

字元串str:用引號括起來的文本(如:'python'、'123'、'風變編程')

整數int:不帶小數點的數字(如:-1、1、0、520、1314)

浮點數float:帶小數點的數字,運算結果存在誤差(如:-0.15、3.1415、1.0)

以下的數據結構會有一節或兩節的課程介紹,可輕松上手。

列表list:是一種悶畢有序的集合,可以隨時增加或刪除其中的元素。標識是中括弧[]。

元組tuple:一種類似列表的數據類型,但是不能被修改。

字典dice:全稱為dictionary,使用鍵值對(螞彎芹key-value)作為存儲方式。標識是大括弧{}。

布爾值bool:表示真假的數據類型,只有兩個值,True和False。

數據的操作
字元串的拼接
初階用法:使用 ' + ' 進行字元串的拼接

>>>print('風變'+'編程')

風變編程

>>>name = '醬醬'

>>>begin = '我叫'

>>>print(begin + name)

我叫醬醬

進階用法:使用 ' % ' 進行字元串的拼接

>>>name = '《鳳求凰》'

>>>number = 1

>>>print('司馬相如以%d曲%s打動了卓文君' %(number,name))

司馬相如以1曲《鳳求凰》打動了卓文君

四則運算
運算符 表示 例子
+ 加 1 + 1 輸出結果為2
- 減 1 - 1 輸出結果為0
* 乘 3 * 2 輸出結果為6
/ 除 2 / 1 輸出結果為2
% 取模-返回除法的余數 5 % 2 輸出結果為1
** 冪-返回x的y次冪 2 ** 3 輸出結果為8
// 取整除-返回商的整數部分 11 // 2 輸出結果為5
運算優先順序:

與平時運算優先順序一樣:從左到右順著來,括弧里的優先算,乘除排在加減前。

數據轉換
type()

#查看變數的數據類型

>>>who = 'xiaojiangjiang'

>>>print(type(who))

<class 'str'>

#結果顯示這是一個字元串類型的數據

str()

#將其他數據類型強制轉換為字元串

>>>begin = '我吃了'

>>>number = 1

>>>fruit = '個水果'

>>>print(begin + str(number) +fruit)

我吃了1個水果

#進行字元串拼接時,不同數據類型不能直接使用'+'連接,需要現將整數轉化為字元串類型

int()

#將整數形式的字元串轉化為整數(文本類字元串和浮點形式的字元串不能轉化為整數)

#對浮點數直接抹零取整

>>>print(int(3.8))

3

float()

#將整數和字元串轉換為浮點數(文字類字元串無法轉換)

>>>print(float(8))

8.0

list()

#將數據轉換為列表類型

>>>a = 'python小課'

>>>print(list(a))

['p', 'y', 't', 'h', 'o', 'n', '小', '課']

len()

#用於檢查某個數據的長度

>>>bros = ['劉備','關羽','張飛']

>>>print(len(bros))

3

>>>emotion = 'happy'

>>>print(len(emotion))

5

數據的常用語法
列表語法
列表的操作可分為兩種類型,一種類型為對列表元素的處理,另一種類型為對列表的處理,每種類型都有四種操作:提取,修改,增加,刪除(取改增刪)。

偏移量:對列表元素的位置編號。

#列表的偏移量從0開始計算

#如果要提取一段列表,需要使用切片的形式[a:b]:從a到b的元素,但不包括b(a <= X < b);冒號某側如果沒有數字,則全取

>>>list = ['松','竹','梅']

>>>print(list[0])

>>>print(list[1:2])

>>>print(list[:2])



['竹']

['松','竹']

#松,竹,梅三者的偏移量分辨是0,1,2。

列表元素的提取

>>>list = ['松','竹','梅']

>>>print(list[0])



>>>list = [['松','松樹'],['竹','竹子'],['梅','梅花']]

>>>print(list[0][1])

松樹

#嵌套列表的提取

列表元素的修改

>>>list = ['松','竹','梅']

>>>list[0] = '松樹'

>>>print(list)

['松樹', '竹', '梅']

列表元素的增加

append()

#是列表的方法,在括弧內添加一個元素,可以將該元素添加到列表末尾

>>>list = ['松','竹']

>>>list.append('梅')

>>>print(list)

['松','竹','梅']

易錯一:用append時不能對列表賦值

>>>list = ['松','竹']

>>>list = list.append('梅')

>>>print(list)

None

#第二行語法錯誤

易錯二:append後面是小括弧,而非中括弧

>>>list = ['松','竹']

>>>list.append['梅']

>>>print(list)

TypeError: 'builtin_function_or_method' object is not subscriptable

#第二行語法錯誤

易錯三:append不能一次添加多個元素

>>>list = ['松','竹']

>>>list.append('梅','歲寒三友')

>>>print(list)

TypeError: append() takes exactly one argument (2 given)

#第二行語法錯誤

列表元素的刪除

del

#刪除命令

易錯一:每次只能刪除一個元素,

易錯二:刪除多個元素時,要重新計算偏移量

>>>list = ['松','竹','梅']

>>>del list[0]

>>>print(list)

>>>del list[0]

>>>print(list)

['竹', '梅']

['梅']

列表的切片(即列表層面的提取,一次提取若干個元素)

>>>list = ['松','竹','梅']

>>>print(list[1:2])

>>>print(list[:2])

['竹']

['松','竹']

#注意:列表的切片提取出來的是列表

列表的修改

#同樣是使用賦值語句,注意是對列表的賦值

>>>list = ['松','竹','梅']

>>>list[:] = ['歲寒三友']

#list[:]表示將列表的所有元素取出來

>>>print(list)

['歲寒三友']

#注意以下的錯誤做法:

>>>list = ['松','竹','梅']

>>>list[:] = '歲寒三友'

>>>print(list)

['歲', '寒', '三', '友']

列表的增加

列表的增加叫作列表的合並會更合理

#使用符號'+'

#符號'+'只能用在列表之間,不能用在列表和元素之間

>>>list1 = ['松']

>>>list2 = ['竹']

>>>list3 = ['梅']

>>>list = list1 + list2 +list3

>>>print(list)

['松', '竹', '梅']

列表的刪除

del

#刪除命令

>>>list = ['松','竹','梅']

>>>del list[:2]

>>>print(list)

['梅']

字典語法
字典數據的提取

#列表使用偏移量來提取,字典使用鍵來提取

>>>group = {'師父':'唐三藏', '大師兄':'孫行者', '二師兄':'豬八戒', '沙師弟':'沙和尚'}

>>>print(group['師父'])

唐三藏

字典數據的修改

>>>group = {'師父':'唐三藏', '大師兄':'孫行者', '二師兄':'豬八戒', '沙師弟':'沙和尚'}

>>>group['師父']='唐玄奘'

>>>print(group)

{'師父': '唐玄奘', '大師兄': '孫行者', '二師兄': '豬八戒', '沙師弟': '沙和尚'}

字典數據的增加

>>>group = {'師父':'唐三藏', '大師兄':'孫行者', '二師兄':'豬八戒', '沙師弟':'沙和尚'}

>>>group['白龍馬']='敖烈'

>>>print(group)

{'師父': '唐三藏', '大師兄': '孫行者', '二師兄': '豬八戒', '沙師弟': '沙和尚', '白龍馬': '敖烈'}

字典數據的刪除

>>>group = {'師父':'唐三藏', '大師兄':'孫行者', '二師兄':'豬八戒', '沙師弟':'沙和尚'}

>>>del group['師父']

>>>print(group)

{'大師兄': '孫行者', '二師兄': '豬八戒', '沙師弟': '沙和尚'}

dict.keys()

#提取字典中所有的鍵

>>>group = {'師父':'唐三藏', '大師兄':'孫行者', '二師兄':'豬八戒', '沙師弟':'沙和尚'}

>>>print(group.keys())

dict_keys(['師父', '大師兄', '二師兄', '沙師弟'])

#列印出了所有字典的鍵,但是都是元組的形式

>>>group = {'師父':'唐三藏', '大師兄':'孫行者', '二師兄':'豬八戒', '沙師弟':'沙和尚'}

>>>print(list(group.keys()))

['師父', '大師兄', '二師兄', '沙師弟']

#通過list()函數將元組轉化為列表的形式

dict.values()

#提取字典中所有的值

>>>group = {'師父':'唐三藏', '大師兄':'孫行者', '二師兄':'豬八戒', '沙師弟':'沙和尚'}

>>>print(group.values())

dict_values(['唐三藏', '孫行者', '豬八戒', '沙和尚'])

dict.items()

#提取字典中所有的鍵值對

>>>group = {'師父':'唐三藏', '大師兄':'孫行者', '二師兄':'豬八戒', '沙師弟':'沙和尚'}

>>>print(group.items())

dict_items([('師父', '唐三藏'), ('大師兄', '孫行者'), ('二師兄', '豬八戒'), ('沙師弟', '沙和尚')])

產生布爾值的表達式
bool()

#檢查數值的真假

>>>print(bool(1))

True

值本身作為條件

假的 其他都是真的
False True
0 5(任意整數)1.0(任意浮點數)
''(空字元串) '風變編程'(字元串)
[](空列表) [1,2,3]
{}(空字典) {1:'a',2:'b'}
None
比較運算符產生布爾值

運算符 釋義 作用
== 等於 如果兩側的值相等,條件為真
!= 不等於 如果兩側的值不相等,條件為真
> 大於 如果左側的值大於右側,條件為真
< 小於 如果左側的值大於右側,條件為真
>= 大於等於 如果左側的值大於或等於右側,條件為真
<= 小於等於 如果左側的值小於或等於右側,條件為真
注意:運算符之間不用空格,不可以寫成= =、> =
成員運算符產生布爾值

運算符 釋義 作用
in 屬於 如果值在指定序列里,條件為真
not in 不屬於 如果值不在指定序列里,條件為真
邏輯運算符產生布爾值

運算符 釋義 作用
and 且 連接兩個布爾值,如果兩個都為真,該條件才為真
or 或 連接兩個布爾值,如果有一個為真,該條件即為真
not 非 反邏輯狀態,a為True,not a則為False,反之亦然
三、循環
for循環
for循環的基本格式是:for…in…

#遍歷字元串

>>>for i in 'coding':

... print(i)

c

o

d

i

n

g

#遍歷列表

>>>for i in ['for','change']

... print(i)

for

change

for…in dict:

#遍歷字典的鍵

>>>list = {1:'a',2:'b',3:'c'}

>>>for i in list:

... print(i)

1

2

3

for…in dict.values():

#遍歷字典的值

>>>list = {1:'a',2:'b',3:'c'}

>>>for i in list.values():

... print(i)

a

b

c

for…in dict.items():

#遍歷字典的鍵值對

>>>list = {1:'a',2:'b',3:'c'}

>>>for k, v in list.items():

... print(k)

... print(v)

1

a

2

b

3

c

range()函數

#range()有最基本的三種用法:range(b), range(a,b),range(a,b,c)。

#函數中各個數值的意義:a:計數從a開始。不填時,從0開始;b:計數到b結束,但不包括b;c:計數的間隔,不填時默認為1。

>>>range(5)

#計數依次為0,1,2,3,4

>>>range(1,5)

#計數依次為1,2,3,4

>>>range(2,8,2)

#計數依次為2,4,6

for…in range()

#處理指定次數的循環

>>>for i in range(3):

... print('第%d遍風變編程' %i)

第0遍風變編程

第1遍風變編程

第2遍風變編程

while循環
while循環

#當條件為真時,執行循環語句,只要條件為真,便會一直循環

>>>count = 3

>>>while count > 1:

... print('happy coding')

... count = count -1

happy coding

happy coding

while循環和for循環的區別:

#for擅長處理固定次,自動遍歷各序列

#while處理不定次數的循環,條件為False便停止

循環進階
break

#如果滿足條件,則結束循環

>>>while True:

... print('happy coding')

... break

happy coding

#break會結束循環,如果只有前兩行代碼,會無限循環列印happy coding

>>>count = 3

>>>while count >1:

... print('happy coding')

... count = count - 1

... if count == 2: #當count等於2的時候,停止循環

... break

happy coding

#對比while循環的例子,我們發現這里只列印了一次happy coding

continue

#如果滿足條件,則跳過當前循環的剩餘語句,直接開始下一輪循環

count = 3

while count >1:

print('happy')

count = count - 1

if count == 2: #當count等於2的時候,跳過下列語句,重新開始新的一輪循環

continue

print('coding') #由於continue語句,coding只會列印一次

#列印的結果為:

happy

happy

coding

else

#無論是否進入循環,最後都會執行esle語句,除非執行break語句跳出循環

count = 3

while count >2:

print('在風變')

count = count -1

else: #無論是否進入循環都會執行else語句

print('happy coding')

#列印結果為:

在風變

happy coding

循環嵌套

#即循環中有循環

>>>for i in ['風變','編程']: #首先遍歷列表元素

... for t in i: #然後遍歷元素(字元串)

... print(t)









四、函數
函數基本知識
函數
函數是組織好的、可以重復使用的、用來實現單一功能的代碼

函數類型可分為自定義函數和內置函數,自定義函數是需要自己定義,而內置函數是python內部已經定義好的函數,比如print()、input()等

函數定義的語法
def

#定義函數

return

#函數的返回值

#函數定義的格式

def 函數名(參數):

函數體

return 語句

#一個簡單的例子

def math_func(x):

y = x + 5

print(y)

return y

math_func(2)

#列印結果為7

變數作用域
變數作用域可認為是變數作用的范圍

全局變數:在全局內生效的變數

局部變數:只能函數內或者一定代碼塊內生效

global

#將局部變數轉化為局部變數

python內置函數
五、類與對象
概念
類:具有相同屬性和方法的對象的抽象

實例:類的個例

對象:Python中的對象是類和實例的集合,類可以看作是對象,實例也可以看作是對象

基本語法
class

#定義類,注意類名需要大寫

class MyClass: #定義類MyClass

i =12345 #定義類的屬性(變數)

def f(self): #定義類的方法

return('hello world') #執行這個方法會返回'hello word'這個字元串

x = MyClass() #創建類的實例x

print(x.i) #列印實例x的屬性

print(x.f()) #列印實例x的f方法

#輸出的結果為

12345

hello world

class A(B)

#定義B類的子類A類,A類具有B類的屬性和方法,也將B類稱為A類的父類

class SecondClass(MyClass):

pass

#定義SecondClass是MyClass的子類,SecondClass可以調用MyClass的屬性和方法

x = SecondClass()

print(x.i)

print(x.f())

#輸出的結果為

12345

hello world

class A(B, C)

#多重繼承,A類同時是B類和C類的子類,A類在調用屬性和方法的時候,會優先調用位於左側的類

class B:

i = 123 #B類的屬性是i=123

class C:

i = 12345 #C類的屬性是i=12345

class A(B,C): #A類是B類和C類的子類

pass

x = A() #創建A類的實例x

print(x.i) #調用屬性,會優先調用B類的屬性

#結果輸出為

123

def __init__(self):

#創建類的初始化方法,只要調用類,便自動調用初始化方法的語句,常用於創建實例屬性

>>>class A:

... def __init__(self): #只要創建實例,便會自動執行初始化方法下的語句

... print('hello world')

>>>x = A()

hello world #只要創建實例就會調用方法,列印hello world

#對比以下沒有初始化的方法:

>>>class A:

... def f(self):

... print('hello world')

>>>x = A()

#不使用初始化方法,創建實例無任何輸出

super()

#在子類的方法里調用父類的方法,使子類的方法可以在繼承父類方法的基礎上進行擴展

123 def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1]
cls代表類,inst代表實例,可以看出上面的代碼做了兩件事:

· 獲取inst的MRO列表。

· 查找cls在MRO的index,並返回它的下一個類,即mro[index + 1]

當你使用super(cls, inst)時,python會在inst的MRO列表上搜索下cls的下一個類。

六、模塊與庫
模塊類型
內置模塊

#python官方組織編寫和維護的模塊

自定義模塊

#自己寫代碼,然後將代碼塊保存為 .py 文件

第三方模塊

#從自定義模塊而來,代碼寫作者公開自己的代碼

#根據模塊的組織形式的不同,也可分為單個模塊文件、模塊包、模塊庫

模塊和模塊對象導入方法
import A

#導入模塊A

#現在可以調用模塊里函數和變數,但是必須通過【模塊名.函數名()】和【模塊名.變數名】的方式調用

#創建類實例的時候,需要使用【實例名 = 模塊名.類名()】進行創建,創建實例後調用類方法和屬性可以使用【實例名.函數名()】和【實例名.變數名】

import A as a

#導入模塊A,並將模塊A重新命名為a

#調用模塊中的類、函數和變數如上述操作一樣

from A import B

#導入模塊A中的對象B

#調用對象B中的函數和變數可以不加模塊名

from A import B,C,D

#導入模塊A中的多個對象B,C,D

from A import *

#導入模塊A中的所有對象

if __name__=="__main__":

#當.py文件被直接運行時,if __name__=="__main__":之下的代碼塊將被運行

#當.py文件以模塊形式被導入時,if __name__=="__main__":之下的代碼塊不被運行

七、文件讀寫
文件讀寫三步驟
第一步,打開文件

第二步,讀(寫)文件

第三步,關閉文件

打開文件語法
open(file, mode, encoding)

#打開文件

f = open('/letter.txt', 'r', encoding = 'UTF-8')

with open() as…

#使用這種方式打開文件,可以不使用close()關閉文件

with open('/letter.txt', 'r', encoding = 'UTF-8') as f:

讀寫模式mode

模式mode 操作 若不存在 是否覆蓋
r 只能讀不能寫 報錯 -
rb 二進制只讀 報錯 -
r+ 可讀可寫 報錯 是
rb+ 二進制讀寫 報錯 是
w 只能寫不能讀 創建文件 是
wb 二進制只寫 創建文件 是
w+ 可讀可寫 創建文件 是
wb+ 二進制讀寫 創建文件 是
a 追加不能讀 創建文件 否,追加寫
ab 二進制追加不能讀 創建文件 否,追加寫
a+ 可讀可寫 創建文件 否,追加寫
ab+ 二進制追加可讀可寫 創建文件 否,追加寫
讀寫文件語法
read()

#讀取文件內容

with open('/letter.txt','r',encoding = 'UTF-8') as f:

content = f.read()

#以字元串的形式讀取文件內容,將文件內容賦值給變數content

readlines()

#以列表的方式讀取文件內容

with open('/letter.txt','r',encoding = 'UTF-8') as f:

content = f.readlines()

#以列表的形式讀取文件內容,將文件內容賦值給變數content

write()

#清空文件內容,並寫入字元串入內容

with open('/letter.txt','r',encoding = 'UTF-8') as f:

f.write('python')

writelines()

#清空文件內容,以列表的方式寫入

with open('/letter.txt','r',encoding = 'UTF-8') as f:

f.writelines('python')

關閉文件語法
close()

#關閉文件

csv文件讀寫的相關函數

reader()

#讀取csv文件的函數

import csv #導入csv模塊

with open('letter.csv') as f:

reader = csv.reader(f) #讀取csv文件,將文件內容賦值到reader

writer()

#將內容寫入csv文件

writerow()

#寫入一行內容

writerows()

#一次寫入多行csv文件

import csv #導入csv模塊

with open('letter.csv','w',newline = '') as f:

writer = csv.writer(f) #寫入csv文件

writer.writerow(['python小課','風變編程']) #寫入一行內容

data = [['互動式學習','更簡單'],['助教醬醬','為你答疑解惑']]

writer.writerows(data) #寫入多行內容

os模塊

os.getcwd()

#返回當前的工作目錄

八、debug
try…except…語句

用於處理

for i in range(6):

try:

print(6/i)

#使用6依次除於0,1,2,3,4,5,並列印

except ZeroDivisionError

#除非發生ZeroDivisionError類型的錯誤,執行下列語句

print('0是不能做除數的!')

九、其他
str.spilt()

#返回一個由字元串內單片語成的列表

>>>'1,2,3'.split()

['1',',','2',',','3']

>>>'1,2,3'.split('?,')

['1','2','3']

random模塊

#隨機模塊

import random

#需要先導入random模塊,然後再調用相應方法

print(random.randint(1,10)) # 產生 1 到 10 的一個整數型隨機數

print(random.random()) # 產生 0 到 1 之間的隨機浮點數

print(random.uniform(1.1,5.4)) # 產生 1.1 到 5.4 之間的隨機浮點數,區間可以不是整數

print(random.choice('tomorrow')) # 從序列中隨機選取一個元素

print(random.randrange(1,100,2)) # 生成從1到100的間隔為2的隨機整數

轉義字元

轉義字元 意義
a 響鈴(BEL)
b 退格(BS),將當前位置移到前一列
f 換頁(FF),將當前位置移到下頁開頭
n 換行(LF),將當前位置移到下一行開頭
r 回車(CR),將當前位置移到本行開頭
t 水平製表(HT) (跳到下一個TAB位置)
v 垂直製表(VT)
代表一個反斜杠字元""
' 代表一個單引號(撇號)字元
" 代表一個雙引號字元
? 代表一個問號
0 空字元(NUL)
ddd 1到3位八進制所代表的任意字元
xhh 1到2位十六進制所代表的任意字元
注意1:區分斜杠「/」和反斜杠「」,此處不可互換。注意2:以上表格內容也不需要硬記。

6. 又來求助了,大神求解答 python類繼承的問題

老式類就是經典類,不是繼承自object類.在多繼承時採用深度優先遍歷父類.
新式類就是基類繼承自object類 class xxx(object).多繼承時採用一種新的C3 演算法來遍歷父類.
實例如下:

新式類的打配絕印結果如下:

1speak: I am mother

舊式類的列印結果如下:

1speak: I am GrandFather

由此我們可以看出新式類的搜索過程為:Son-->Father-->Mother,而舊式類的搜索過程為:Son-->Father-->GrandFather

我們可以看出舊式類和我們預期的繼承不太一樣。

老式類就是經典類,不是繼承自object類.在多繼承時採用深度優先遍歷父類.
新式類就是基類繼承自object類 class xxx(object).多繼承時採用一種新的C3 演算法來遍歷父類.

為什麼採用C3演算法呢?

C3演算法最早被提出是用於Lisp的,應用在Python中是為了解決原來基於深度優先搜索演算法不滿足本地優先順序,和單調性的問題。

本地優先順序:指聲明時父類的順序,比如C(A,B),如果培虧姿訪問C類對象屬性時,應該根據聲明順序,優先查找A類,然後再查找B類。

單調性:如果在C的解析順序中,A排在B的前面,那麼在C的所有子類里,也必須滿足這個順序。

為了解釋C3演算法,我們引入了mro(mro即 method resolution order (方法解釋順序),主要用於在多繼承時判斷屬性的路徑(來自於哪個類))。

我們可以通過class.mro()來查看python類的mro

C3演算法
判斷mro要先確定一個線性序列,然後查找路徑由由序列中類的順序決定。所以C3演算法就是生成一個線性序列。
如果繼承至一個基類:
class B(A)
這時B的mro序列為[B,A]

如果繼承至多個基類
class B(A1,A2,A3 ...)
這時B的mro序列 mro(B) = [B] + merge(mro(A1), mro(A2), mro(A3) ..., [A1,A2,A3])


merge操作就是C3演算法的核心。
遍歷執行merge操作的序列,如果一個序列的第一個元素,是其他序列中的第一個元素,或不在其他序列出現,則從所有執行merge操作序列中刪除這個元素,合並到當前的mro中。
merge操作後的序列,繼續執行merge操作,直到merge操作的序列為空。
如果merge操作的序列無法為空,則說明不合法。

例子:
class A(O):pass
class B(O):pass
class C(O):pass
class E(A,B):pass
class F(B,C):pass
class G(E,F):pass

A、B、C都繼承至一個基類,所以mro序列依次為[A,O]、[B,O]、[C,O]
mro(E) = [E] + merge(mro(A), mro(B), [A,B])
= [E] + merge([A,O], [B,O], [A,B])
執行merge操作的序列為[A,O]、[B,O]、[A,B]
A是序列[A,O]中的第空拿一個元素,在序列[B,O]中不出現,在序列[A,B]中也是第一個元素,所以從執行merge操作的序列([A,O]、[B,O]、[A,B])中刪除A,合並到當前mro,[E]中。
mro(E) = [E,A] + merge([O], [B,O], [B])
再執行merge操作,O是序列[O]中的第一個元素,但O在序列[B,O]中出現並且不是其中第一個元素。繼續查看[B,O]的第一個元素B,B滿足條件,所以從執行merge操作的序列中刪除B,合並到[E, A]中。
mro(E) = [E,A,B] + merge([O], [O])
= [E,A,B,O]

7. Python中的多繼承

單繼承:一個派生類的基類只有一個
多繼承:一個派生類的基類有多個
一句話區分就是:單繼承是一個生一個,多繼承是多個生一個
多繼承的基本語法:

子類定義構造方法時,需要將父類的構造方法調用一次。
案例演示:

在則答掘多繼承中,所有基類的方法可以直接繼承,但是屬性需要手工初始舉閉化。如果派生類中沒有 __init__ 方法,則默認獲得第一個類的屬性。如果派生類中有 __init__ 方法,則所有基類的屬性都不會獲得,需要手動逐孫核一初始化。

我們定義一個ChineseStudent類,其繼承關系如下:

調用基類的屬性和方法

在不同的基類中存在相同的方法,派生類對象調用方法時會調用哪個父類的方法呢?
默認情況下,如果多個基類中有相同的方法,越在前面,優先順序越高。
為了避免後期沒必要的錯誤,建議基類之間存在重名的屬性和方法應該盡量避免。

MRO(Method Resolution Order)方法解析順序

如果是經典類(舊式類),MRO的方法--DFS(深度優先搜索)策略

如果是新式類,MRO的方法--BFS(廣度優先搜索)策略

8. 怎麼理解python方法__mro_entries__,__orig_bases__

def __mro_entries__(self, bases):
如果在類定義中出現的基類不是 type 的實例, 則使用 __mro_entries__ 方法對雀運其進行搜索
當找到結果時, 它會以原始基類元組做參數進行調用
此方法必須返回類的元組以替顫茄代此基類被使用
元組可以為空, 在此情況下原始基類將被忽略
__mro_entries__獲取origin變茄歲察量
__class_getitem__返回一個實例化的

熱點內容
php辦公系統 發布:2025-07-19 03:06:35 瀏覽:900
奧德賽買什麼配置出去改裝 發布:2025-07-19 02:53:18 瀏覽:42
請與網路管理員聯系請求訪問許可權 發布:2025-07-19 02:37:34 瀏覽:189
ipad上b站緩存視頻怎麼下載 發布:2025-07-19 02:32:17 瀏覽:844
phpcgi與phpfpm 發布:2025-07-19 02:05:19 瀏覽:527
捷達方向機安全登錄密碼是多少 發布:2025-07-19 00:57:37 瀏覽:694
夜魔迅雷下載ftp 發布:2025-07-19 00:39:29 瀏覽:99
增值稅票安全接入伺服器地址 發布:2025-07-19 00:20:45 瀏覽:486
solidworkspcb伺服器地址 發布:2025-07-18 22:50:35 瀏覽:823
怎麼在堆疊交換機里配置vlan 發布:2025-07-18 22:42:35 瀏覽:630