深刻理解python中的類和對象

深刻理解python中的類和對象

sergiojune 平常學python
剛開始學習python的時候或者其餘的是面向對象的編程語言的時候,不免會對類和對象理解得不太清楚。因此今天和你們分享下python中的類和對象,深刻理解下python中的類和對象。python

1.鴨子類型

當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就能夠被稱爲鴨子。這個就是鴨子類型的定義,在python中,並不關心這個對象是什麼類型,只關心他的行爲。由行爲來推斷出該對象所屬於的類型。就好比列表(list)、元組(tuple)、字典(dict)等等,這些類都是可迭代的,因此說他們是可迭代對象。算法

from collections import Iterable
l = [1, ]
t = (1, )
d = {'d': 3}
print(isinstance(l, Iterable))
print(isinstance(t, Iterable))
print(isinstance(d, Iterable))

# 結果
True
True
True

2.類變量和實例變量

類變量就是在類內定義的,可是不在方法內定義的,並且前綴無self做爲引用。實例變量就是有self做爲引用的存在類中的變量。類變量是全部對象共享的,在類中修改時,其餘的對象也會跟着變。可是須要注意的是,若是是用對象來引用類變量進行修改的話,這裏只是新建了和類變量同名的實例變量,並無修改到。下面用代碼解釋下。編程

class Student(object):
   conutry = 'China'  # 這個是類變量

   def __init__(self, name, sex):
       self.name = name  # 這個是實例變量,也就是對象變量
       self.sex = sex  # 對象變量

s1 = Student('張三', 'man')
s2 = Student('里斯', 'woman')
print(s1.conutry)
print(s2.conutry)
print(Student.conutry)

上面的結果都是三個China,這個很容易知道,用類來引用改變時markdown

Student.conutry = 'cn'  # 這個是用類引用來進行修改

修改後打印下三個結果都是修改後的結果。可是下面這個呢?編程語言

s1.conutry = 'zhongguo'  # 用實例來引用進行修改

此次結果就不同了,只有s1的類變量變了,其餘兩個都是不變的。這是爲何呢?就如上面所說,用實例引用來修改類變量的時候並非修改,而是新建了這個變量。又因爲python查找變量是由下往上查找的,因此會先查找出新建後的變量。ide

3.類屬性和實例屬性之間的訪問順序

類屬性就是定義在類中的方法和變量,實例屬性也是同樣的。訪問順序就是由下往上查找的,用代碼體會一下。函數

class A():
   name = 'A'
   def __init__(self):
       self.name = 'a'

a = A()
print(a.name)
# 結果
a

因爲是類變量先加載,再到初始化對象,因此纔會運行init()方法,因此結果很顯然就是a。這裏因爲該類沒有繼承,就沒有很複雜,可是當出現多繼承,幾個類之間就變得很複雜,這個時候的訪問順序就難多了。下面說下這兩種狀況,掌握了這兩種狀況,其餘的基本沒有問題了。學習

(1.適合深度優先查找
深刻理解python中的類和對象
A繼承了B,C,B,C分別繼承了D,E。深度優先的查找是先去着A,若是A中沒有該屬性,就去B着,再沒有就去D找。D中找不到了再去C找。這種查找狀況是沒有問題的,可是另外一種狀況就不合適了。code

2)適合廣度優先查找
深刻理解python中的類和對象
這個是A繼承了B,C,B,C都繼承了D。若是這個用深度優先的算法的話,就會出現一個問題,由於深度優先查找順序是A->B->D->C。這個是不太合理的,當C中重載了D中的一個方法後,B沒有重載,若是要查找C中的該方法,用深度優先的算法就只能找到D中的原始方法,因此說這就不正確了,這時候就須要用廣度優先的 算法,這個時候查找順序就是A->B->C->D。可是當遇到上面的狀況時又會出錯了。這時怎麼辦?python3就將全部的屬性搜索算法統一成了一個算法:C3算法,這裏就不展開說這個算法了,由於太複雜了:)會根據對應狀況而實施對應算法,下面用代碼來分別體會下以上兩種狀況對象

class E():
   pass

class D():
   pass

class C(E):
   pass

class B(D):
   pass

class A(B, C):
   pass

print(A.__mro__)
# 結果
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)

mro這個屬性是獲取屬性的查找順序,能夠看到就是和咱們上面說的同樣,用了深度優先的算法。再看另外一個

class D():
   pass

class C(D):
   pass

class B(D):
   pass

class A(B, C):
   pass

print(A.__mro__)
# 結果
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)

這個時候就用了廣度優先算法,符合與咱們剛纔所說的,這就是C3算法了哈。

4.super真的是調用父類嗎?

學過Java的都知道,super()這個方法就是在調用父類的方法,可是在python中就不必定了。咱們先看看super的用法

class A():
   def __init__(self):
       print('A')

class B(A):
   def __init__(self):
       # python2作法是
       # super(A, self).__init__()
       super().__init__()  # 調用父類的初始化方法
       print('B')

b = B()
# 結果
A
B

上面就是用法了,python2和python3用法不同,這裏咱們就只用python3了就行操做。接下來看看super真正的調用狀況。

class A():
   def __init__(self):
       print('A')

class B(A):
   def __init__(self):
       super().__init__()
       print('B')

class C(A):
   def __init__(self):
       super().__init__()
       print('C')

class D(B, C):
   def __init__(self):
       super().__init__()
       print('D')

d = D()

上面這個是咱們以前所說的那個適合廣度優先算法的多繼承,按照咱們以前的理解,super調用的是父函數,那麼這個結果就會是:

A  
      B  
      C 
      D

顯然是錯誤,結果是這個

深刻理解python中的類和對象

是否是以爲很奇怪,可是又很熟悉?是的,這個也是按照剛纔的查找順序同樣執行的,若是不信的話咱們打印下mro就知道了

是否是恰好倒敘?由於咱們是先打印父類的再打印本身的,因此順序倒了。再看看另一種狀況也是可行的

class A():
   def __init__(self):
       print('A')

class B():
   def __init__(self):
       super().__init__()
       print('B')

class C(A):
   def __init__(self):
       super().__init__()
       print('C')

class D(B):
   def __init__(self):
       super().__init__()
       print('D')

class E(D, C):
   def __init__(self):
       super().__init__()
       print('E')

e = E()
print(E.__mro__)
# 結果
A
C
B
D
E
(<class '__main__.E'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

也是和預期同樣的。總的來講,super不必定是調用父類,它的調用順序也是遵循mro算法的,就是屬性查找算法,和上文說的C3算法一致。

有任何問題歡迎在留言區提問,或者有不當的地方也歡迎指出

ps:若是以爲文章不錯的話,歡迎隨手點贊轉發支持

相關文章
相關標籤/搜索