2017-02-03 33 views
2

你會如何提出這個有趣的(至少對我來說)例子。與自己調用類變量

import numpy as np 


class Something(object): 
    a = np.random.randint(low=0, high=10) 

    def do(self): 
     self.a += 1 
     print(self.a) 

if __name__ == '__main__': 
    something = Something() 
    print(something.__str__()) 
    something.do() 
    something2 = Something() 
    print(something2.__str__()) 
    something2.do() 
    something3 = Something() 
    print(something3.__str__()) 
    something3.do() 

上面打印在控制檯以下:

$ python test.py 
<__main__.Something object at 0x7f03a80e0518> 
1 
<__main__.Something object at 0x7f03a80cfcc0> 
1 
<__main__.Something object at 0x7f03a80cfcf8> 
1 

我有點困惑,因爲我(錯誤地)假定a價值將有所增加。

如果我使用@classmethod修飾符,我可以獲得我期望的行爲。

import numpy as np 


class Something(object): 
    a = np.random.randint(low=0, high=10) 

    @classmethod 
    def do(cls): 
     cls.a += 1 
     print(cls.a) 

if __name__ == '__main__': 
    something = Something() 
    print(something.__str__()) 
    something.do() 
    something2 = Something() 
    print(something2.__str__()) 
    something2.do() 
    something3 = Something() 
    print(something3.__str__()) 
    something3.do() 

這會在控制檯中正確打印以下內容。現在

python test.py 
<__main__.Something object at 0x7faac77becc0> 
3 
<__main__.Something object at 0x7faac77becf8> 
4 
<__main__.Something object at 0x7faac77c3978> 
5 

,我想知道在第一個例子,當我打電話self.a,就是我訪問?這不是一個類變量,因爲我似乎無法改變它的價值。它也不是一個實例變量,因爲這似乎是在同一個類的不同對象之間共享的。你會怎樣稱呼它?

這是一個類的變量,我用錯了方式?我知道cls這個名字,如果一個約定,所以也許我真的在訪問一個類變量,但是我不能修改它的值,因爲我沒有使用@classmethod修飾符修飾方法。

這是一種非法使用該語言嗎?我的意思是最好不要做,以避免在後期階段引入錯誤。

回答

5

正在發生的事情是,self.a是指在不同的時間的事情。

當沒有實例變量存在名稱時,Python將查找該類的值。因此,self.a的檢索值將是類變量。

但當通過self設置屬性,Python會始終設置一個實例變量。所以現在self.a是一個新的實例變量,它的值等於類變量+1。該屬性給類屬性加上陰影,你不能再通過self訪問類屬性,而只能通過類訪問。

(一個小小的點,其中有無關的問題:你永遠不應該直接訪問而不是調用something2.__str__()的雙下劃線方法,調用str(something2)等)

0

由丹尼爾·羅斯曼回答清楚地解釋了問題。這裏有一些額外的觀點,並希望它有幫助。 您可以使用type(self).a而不是self.a.也期待在討論 Python: self vs type(self) and the proper use of class variablesPython: self.__class__ vs. type(self)

import numpy as np 


class Something(object): 
    a = np.random.randint(low=0, high=10) 

    def do(self): 
     type(self).a += 1 
     print(type(self).a) 

if __name__ == '__main__': 
    something = Something() 
    print(str(something)) 
    something.do() 
    something2 = Something() 
    print(str(something2)) 
    something2.do() 
    something3 = Something() 
    print(str(something3)) 
    something3.do()