1. 程式人生 > >python類變數與建構函式的使用

python類變數與建構函式的使用

類變數:可在類的所有例項之間共享的變數 例項類物件:類的例項是呼叫類物件來建立的。如: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()!