python pointer_python 的隐式指针特征与class inheritance
python的隱式指針特征
pointer是C/C++的里非常熟悉也容易令人困惑的一個功能點,python里的變量賦值一般表現也和指針類似,但是沒有顯式地語法指出,·在這里我用自己的理解做一個比喻來幫助大家理解。
當我們寫下一行語句,比如a=1 (python)或者int a=1(C++),電腦內存到底做了什么呢?這里的數據“1”在電腦內存里實際上是一個二級制序列,任何數據最終都以這種形式存儲。而序列儲存的位置,則是這份數據的地址,這個地址在內存中,通過“a”這個代號來獲取。
所以,如果把地址比作是一棟房子,數據就像是房子里裝的家具,而房子門口的門牌號,就是地址的名字。只不過在程序里,一個房子可以有多個門牌號,共同指向同一個房子,但是不能有多個房子,共享同一個門牌號。
a=1,a=2,是更改了a對應房子里存儲的東西(數據)
a=1,b=a,是賦予“1”這個數據所在的房子兩塊門牌號(a,b)
此時修改a,b任意變量名的值,a、b的值均被修改,換句話說,python賦值默認是指針賦值,但是在class內賦值、copy賦值例外。
python class及inheritance
為什么需要class?
答案是我們需要用數據結構來存儲數據的關系,而不是記在腦子里,或者是靠修改變量名稱。比如我們需要程序計算,高中生的各科成績求和。顯然,一個簡單的sum函數可以完成這樣的運算,再來一個for循環,對所有的學生都算一遍。但是這樣做之后,我們無法知道把學生的名字、單科成績、各科成績對應起來,雖然他們在循環中的次序是對應的。如果代碼里稍有不慎修改了成績的原始排序,就會出現驢唇對馬嘴的情況。
class 作為一種復雜的數據結構,能夠幫我們記錄下一個綜合體及其各個屬性的關系,以支持更復雜的操作。
此外還能夠提高代碼可讀性,減少重復代碼塊粘貼,提高效率。
class 數據結構還能繼承,不斷延展功能的同時,不干擾舊的代碼功能,用盡量少的代碼支持更多操作。
基本語法
class A(object):def __init__(self):print('A init called')self.num=1class B(A):def __init__(self):print('B init called')A.__init__(self) a=A() b=B() b.num首先我們定了一個class 結構A,它的初始化/構造函數(類似于C++里的constructor)打印一句話,并且給自己多了一個成員 num,值為1
然后定義了一個class 結構B,B繼承了A,B的構造函數打印了一句話,然后調用了A的構造函數,這里的調用,等同于把A的_init_函數完全復制到B里,并且執行,也就是繼承了A的init
結果是
A init called #a=A()
B init called#b=B()的構造函數print
A init called#b的init里 call A的init,并且給B增加了一個成員self.num
1 #b.num
更規范的繼承寫法
上邊的例子中,在B的init我們指定繼承A的init,形如baseclass._init_(self),這種寫法在一層繼承中沒有問題,但是在多層繼承中,會喪失靈活性,因為此時,parent class被hard-coded,而不是按照繼承鏈自動追溯,喪失了靈活性。
參考這篇文章的例子
What is the difference between old style and new style classes in Python??stackoverflow.comclass上邊的代碼中,Unsuperchild class的繼承寫法是固定的,和上邊的class B一樣。而superchild class的繼承方法是使用了super(括號可以省略)關鍵詞,兩者都繼承自somebaseclass。那么到底有什么后果呢?我們再加入一層繼承
class InjectMe(SomeBaseClass):def __init__(self):print('InjectMe.__init__(self) called')super(InjectMe, self).__init__()class UnsuperInjector(UnsuperChild, InjectMe): passclass SuperInjector(SuperChild, InjectMe): passInjectMe class 也繼承自somebaseclass。同時UnsuperInjector繼承UnsuperChild,和InjectMe,SuperInjector繼承SuperChild,和InjectMe
現在的繼承關系有三級
somebaseclass (grandparent)
unsuperchild superchild InjectMe (parent)
unsuperinjector superinjector (child)
根據Method Resolution Order (MRO)法則,當我生成一個第三級class 的實例時,會按照“先左后右再向上”的順序調用super
比如我創建一個UnsuperInjector的實例,它的左邊parent是UnsuperChild,先調用了UnsuperChild的init,UnsuperChild的init里寫了,固定調用sombaseclass 的init,因此,不用super()關鍵字繼承時,會受到固定parent class的限制,不會再調用injectme class
o = UnsuperInjector() # 打印 UnsuperChild.__init__(self) called #打印 SomeBaseClass.__init__(self) called而如果run下邊一句結果就不同
o2 = SuperInjector() SuperChild.__init__(self) called InjectMe.__init__(self) called SomeBaseClass.__init__(self) calledSuperInjector上一級左邊是SuperChild,SuperChild的init里有super().init,,右邊是InjectMe,也有super().init,因此SuperChild的super 指向InjectMe,InjectMe的super指向SomeBaseClass,因此打印結果如上邊代碼塊所示。
總結
在multiple inheritance模式下,super().繼承方法能夠避免固定繼承導致其他parent class繼承失效的問題,增加了代碼靈活性。同時注意繼承的順序由MRO決定,遵循同級先左后右,再增加深度的原則。
總結
以上是生活随笔為你收集整理的python pointer_python 的隐式指针特征与class inheritance的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【IT之家开箱】一加 11 木星岩图赏:
- 下一篇: 华硕 ROG 游戏手机 7 系列配置曝光