2010-03-11 138 views
5

我一直在試圖理解Python對類和實例變量的處理。特別是,我發現this answer相當有幫助。基本上它說,如果你聲明一個類變量,然後你做了一個分配到[instance].property,你將分配給一個不同的變量 - 一個在不同的名字空間的類變量。對Python類和實例變量的複合賦值

於是我認爲 - 如果我想我的類的每個實例有一些默認值的成員(說零),我應該做這樣的:

class Foo: 
    num = 0 

或這樣嗎?

class Foo: 
    def __init__(self): 
     self.num = 0 

基於我早一點看,我認爲第二個例子是初始化「正確」的變量(實例,而不是類變量)。但是,我發現第一種方法也可以很好地工作:

class Foo: 
    num = 0 

bar = Foo() 
bar.num += 1 # good, no error here, meaning that bar has an attribute 'num' 
bar.num 
>>> 1 
Foo.num 
>>> 0 # yet the class variable is not modified! so what 'num' did I add to just now? 

那麼......爲什麼這樣工作?我沒有得到什麼? FWIW,我之前對OOP的理解來自C++,所以用類比的方式來解釋(或者指出它的分解點)可能是有用的。

回答

5

就我個人而言,我發現Shalabh Chaturvedi的these documents對此主題非常有用和信息豐富。

bar.num += 1bar.num = bar.num + 1的簡寫。這是拾取右側的類變量Foo.num並將其分配給實例變量bar.num

+1

而當我說類/實例'變量'我真正的意思是'屬性'。 – MattH 2010-03-11 11:56:12

0
bar.num += 1 

上的「棒」實例創建一個新的實例變量「NUM」,因爲它不存在(然後加1這個值)

一個例子:

class Foo: 
    def __init__(self): 
    self.num= 1 

bar = Foo() 
print bar.num 

此打印1

print bar.foo 

這給預期的錯誤:回溯(最近通話最後一個): 文件 「」,1號線,在 AttributeError的:富實例沒有屬性 '富'

bar.foo = 5 
print bar.foo 

現在這個打印5

等什麼在你的例子發生:bar.num解析爲Foo。因爲只有一個類屬性。那麼foo.num實際上是因爲您爲其賦值而創建的。

+0

呃......'bar.foo + = 1'也給出了一個錯誤,很明顯Python不會在它遇到它時創建實例變量包含'+ ='的表達式。我的問題是,如何創建類變量導致對應的實例變量的初始化? – int3 2010-03-11 11:40:24

+1

@ int3。這與屬性如何解決有關。當訪問屬性時,首先搜索對象(在這種情況下爲'num'),然後搜索對象的類型('Foo'),然後搜索對象類型的基類和基類。如果沒有找到匹配的屬性,則引發'AttributeError'。確實是 – MattH 2010-03-11 11:54:04

+0

,然後創建實例變量是因爲我們爲它分配了一個值。我會更新示例 – 2010-03-11 11:58:43

-3

我想你剛在Python裏發現了一個bug。 bar.num + = 1應該是一個錯誤,而是在對象欄中創建一個與Foo.num不同的屬性num。

這是一個非常奇怪的行爲。

+0

@Morgaelyn:不,這不是一個錯誤,這是預期的行爲。閱讀python類http://docs.python.org/tutorial/classes.html – MattH 2010-03-11 12:00:01

+0

正如MattH所說,這是有意和有記錄的行爲。所以,不,這不是一個錯誤。 – krawyoti 2010-03-11 13:15:01

+0

現在我明白了。 b.num + = 1與b.num = b.num + 1相同。第一個b.num引用對象屬性並創建。第二個b.num實際上指的是Foo.num,它是0. NOW現在是合理的。我仍然認爲這是該語言的設計錯誤。很容易假設b.num + = 1中的b.num始終指向相同的變量,但它實際上是指同時引用兩個不相關的變量。 – 2010-03-11 13:27:54

2

在以下代碼中,num是一個類成員。

class Foo: 
    num = 0 

A C++當量將像

struct Foo { 
    static int num; 
}; 

int Foo::num = 1; 

class Foo: 
    def __init__(self): 
     self.num = 0 

self.num是一個實例成員(self是的Foo一個實例)。

在C++中,它會像

struct Foo { 
    int num; 
}; 

我認爲,Python允許你有一個類成員和實例成員共享相同的名稱(C++不)。因此,當您執行bar = Foo()時,barFoo的實例,因此使用bar.num += 1時,您將增加實例成員。

+0

您的C++等價物似乎已將num的值遞增1! :) – Kylotan 2010-03-11 12:02:17

0

尋找這個問題,這個StackOverflow問題和Guido van Rossum(1,2)的兩張幻燈片(相當老,但是有效)都出現了很高。 Guido的幻燈片表明,這種行爲與Python的訪問屬性的搜索順序有關(在num以上的例子中)。我認爲把這兩者放在一起很好:)