python類變量與__init__聲明變量的區別


類變量:可在類的所有實例之間共享的變量
實例類對象:類的實例是調用類對象來創建的。如:par = Parent(),par就是類Parent的一個實例類對象。
實例變量(成員變量):同一個類對象可以創建多個實例類對象,類定義中有self標志的變量就是實例變量
 
一個例子,看下面的代碼有個小問題
class MyObject(object): x = 1
    def __init__(self): objectNum = 99
    def changeNum(self, anotherNum): self.objectNum = anotherNum def showNum(self): print("self.num = ", self.objectNum)
什么問題呢,看似構造函數__init__中的變量object在實例化對象的時候會自動創建並初始化為99,其實不然,這里用一個小的測試代碼就可以發現問題。
obj = MyObject() obj.showNum() Traceback (most recent call last): File "class.py", line 24, in <module> obj.showNum() File "class.py", line 20, in showNum print("self.num = ", self.objectNum) AttributeError: 'MyObject' object has no attribute 'objectNum'
報錯了,提示實例化對象MyObject並沒有objectNum這個普通成員變量,為什么呢?
問題就在於,在Python中,類的成員變量必須使用self.propertName進行聲明,這樣才能完成創建,因為self的含義就是代表實例對象;
在這個類中,objectNum和self.objectNum就是兩個完全不同的東西:
定義在__init__函數中的變量objectNum在這里是一個局部變量,不是類變量
 
接下來我們可以再寫一段代碼,調用changNum()方法,來生成這個成員變量self.objectNum:
obj = MyObject() obj.changeNum(10) obj.showNum() >>> self.num =  10
能看到成功返回結果,
由於在changeNum()方法中,有self.objectNum = anotherNum的賦值,而__init__中,沒有創建類普通成員變量self.objectNum, 而是創建了一個臨時變量objectNum,所以在這里,雖然changeNum()沒有被自動調用(因為不是__init__()函數),但是其實充當了創建類成員變量和初始化的作用, 但是python並不會在創建新的實例化對象的時候自動調用它。
 
所以通過實驗得到3個結論:
1.python中的"構造函數"非常的自由,如果不考慮自動調用,任何類方法都可以去創建類成員變量:
class ExampleClass: def createObjectProperty(self, value): self.newObjectProperty = value
如上面的代碼,這里聲明一個類方法,傳入參數self 和 value,調用這個方法,就可以生成一個普通成員變量newObjectProperty,並對其賦初值value
2.如果想要找到真正意義上的成員變量,那么只需要在__init__(self)中聲明self.objectProperty即可
3.python中的self不能隱式調用,如果你不想生成一個臨時變量而是創建一個類成員變量,那么就應該使用self.variableName
class MyObject(object): x = 1
    def __init__(self): self.objectNum = 99
    def changeNum(self, anotherNum): self.objectNum = anotherNum def showNum(self): print("self.num = ", self.objectNum)
obj = MyObject()
# obj.changeNum(10)
obj.showNum()
>>>self.num =  99
知道了成員變量的問題之后,再來討論一下類變量
class MyObject(object): x = 1
    def __init__(self): self.objectNum = 99
    def changeNum(self, anotherNum): self.objectNum = anotherNum def showNum(self): print("self.num = ", self.objectNum) obj = MyObject() print(MyObject.x) >>> 1

 

在聲明類T的時候,我們在所有的方法之外(但是仍在類的作用域中聲明了一個變量classNum),從命名的角度來看,我們希望這是一個類變量,但我們不希望這次又是一個成員變量,測試發現它確實可以由類名直接訪問再試一下能否修改:
MyObject.x = 100
print(MyObject.x) >>> 100
發現可以修改
下面我們驗證一下其是否能被所有實例化對象訪問和修改,並且是否具有全局性。
t1 = MyObject() print(t1.x) >>> 1 t2 = MyObject() print(t2.x) >>> 1 MyObject.x = 1000
print(t1.x) >>> 1000
print(t2.x) >>> 1000 t1.x = 2000
print(t2.x) >>>1000
print(t1.x) >>>2000
print(MyObject.x) >>>1000
 
從以上結果看出類名.類變量名修改其值會導致實例化對象的值全部被改變,但是用實例化對象名.類變量名修改其值,就僅僅改變自己,不會真的改變類變量的數值。
我們來檢查一下內存,看一段代碼:
t2 = MyObject() t1 = MyObject() print(MyObject.x is t1.x) >>>True print(MyObject.x is t2.x) >>>True print(t2.x is t1.x) >>>True --------------------------------------- t2 = MyObject() t1 = MyObject() t2.x = 10
print(MyObject.x is t1.x) >>>True print(MyObject.x is t2.x) >>>False print(t2.x is t1.x) >>>False -------------------------------------- t2 = MyObject() t1 = MyObject() MyObject.x = 100 t2.x = 10
print(MyObject.x is t1.x) >>>True print(MyObject.x is t2.x) >>>False print(t2.x is t1.x) >>>False
看得出來在最開始的時候MyObject.x和實例化對象t1.x與t2.x內存是同一處的,但當直接修改了實例化對象t2.x的數值后t2.x內存的數值便與其他兩個不同,所以直接修改實例化對象的數值會指向新的內存空間,並且不受類變量改變而改變。
總結:
一個類=類變量(可以沒有)+構造函數(必須有,沒有的話默認調用)+成員函數(自己定義,可以沒有)

構造函數中定義了類的成員變量,類的成員變量一定是在構造函數中以self.開頭的變量!

成員函數中可以調用成員變量和類變量!成員函數的形參在類的實例調用該函數時傳遞,成員函數的局部變量在該成員函數內部定義。調用成員函數和調用普通函數一樣,只是成員函數由該函數對應的類調用,即需要寫成xxxx.func()而不是直接使用func()!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM