2013-06-27 476 views
1

我剛開始學習python,對於爲什麼我能夠做到這一點,我很困惑。會有人請解釋爲什麼這個工程:Python類屬性/屬性

class foo(): 
    @property 
    def hello(self): 
     return "hello world" 


if __name__ == '__main__': 
    cli = foo() 
    cli.foo2 = 3 
    print cli.hello #prints hello world 
    print cli.foo2 #prints 3 

它沒有任何意義,我認爲我能夠創建一個新的屬性,當它不存在於原始的類存在分配一個值。有沒有辦法阻止這種行爲,或者有人能夠至少解釋這背後的邏輯?

-edit-我很高興知道這是python中的對象的正常行爲,我不只是做錯了什麼。它通常不適合我,因爲我通常在VBA和C#中工作。從其他人在下面的答案中所說的話,我認爲增加插槽將阻止以這種方式添加到課堂上的任何東西,但也許我不明白。

class foo(): 
    @property 
    def hello(self): 
     return "hello world" 
    __slots__ = [] 

if __name__ == '__main__': 
    cli = foo() 
    cli.foo2 = 3 
    print cli.hello #prints hello world 
    print cli.foo2 #prints 
+0

我試過這種方法,它並沒有爲我工作(如預期) - 既不cli.foo也不cli.foo2被定義爲。 –

+0

@AMADANON:這有點奇怪。 [它適用於我](http://鍵盤。org/U5XOZL5c),以及OP和其他。 – icktoofay

+0

它已被編輯/修復 - 我仍然在我的終端窗口中剪切和粘貼:) –

回答

3

smarter person than me

一個主要原則是,有沒有這樣的事,作爲一個聲明。也就是說,你永遠不會聲明「這個類有一個方法foo」或「這個類的實例有一個屬性欄」,更不用說在這裏存儲對象的類型。您只需定義一個方法,屬性,類等,並添加它。正如JBernardo所指出的,任何方法都可以做同樣的事情。任意限制創建名稱爲__init__的方法的新屬性沒有多大意義。有時候存儲函數__init__這個函數實際上並沒有這個名字(例如裝飾器),這樣的限制會打破這個限制。

現在,這並不普遍。內建類型忽略了這一功能作爲優化。通過__slots__,您也可以在用戶定義的類上阻止此操作。但這僅僅是一個空間優化(不需要爲每個對象使用字典),而不是正確的事情。

如果你想要一個安全網,太糟糕了。 Python不提供它,你不能合理地添加一個,最重要的是,它會被接受該語言的Python程序員避開(閱讀:幾乎所有你想要使用的語言)。測試和紀律,仍然需要很長時間才能確保正確性。如果可以避免並自動測試,請不要使用自由來彌補__init__以外的屬性。我很少有一個AttributeError或邏輯錯誤,因爲這樣的詭計,而那些發生的事情,幾乎全部都被測試抓住了。

+0

我想我會接受這是正常的行爲,然後繼續前進。 – Ripster

0

這是python對象的預期行爲,您可以在創建它們時添加屬性等。你可以,但是,這樣做限制行爲:

class foo(): 
    __slots__ = [] 
    @property 
    def hello(self): 
     return "hello world" 

__slots__變量就是讓你的類不變的,所以你不能屬性添加到它,否則蟒蛇類典型的表現就像你在你的問題中描述的一種方式

另一種選擇是覆蓋設置和刪除屬性,這樣

def __setattr__(self, *args): 
    raise TypeError 
def __delattr__(self, *args): 
    raise TypeError 
+0

即使在添加'__slots__ = []'後,我也能夠正常運行代碼。不知道我是否誤解了插槽應該如何工作? – Ripster

+0

@Ripster它應該按原樣工作,所以我應該發佈的其他解決方案 – Stephan