2016-01-23 49 views
3

我GOOGLE了一堆,似乎無法弄清楚如何真正做到這一點:如何使用模塊的功能在Python類

鑑於我有這樣一個通用的實用方法,以便:

def __square(n): 
    return n*n 

然後我有一些類,我可能想在內部使用這個方法:

def __square(n): 
    return n*n 

class Foo: 
    def __init__(self): 
     self.baz = 2 

    def bar(self): 
     return self.baz + __square(self.baz) 

嗯,這是行不通的。我得到NameError '_Foo__square' is not defined

爲什麼?

正如我已經結束了做這樣的事情解決方法:

class Foo: 
    def __init__(self): 
     self.baz = 2 

    def bar(self): 
     return baz + self.square(self.baz) 

    def square(self,n): 
     return n*n 

但是那種感覺傻傻的我,因爲平方函數無關,與一個Foo實例,也不會想到我還是希望它成爲Foo實例的一種方法。

什麼是處理這種事情的「pythonic」方式?

編輯

我想通了,這至少一部分:我得到這個行爲,因爲我覺得這些實用方法爲私有的,我已經命名他們像def __square(n):

我沒有意識到這很特別,當輸入上面的例子時,我最初並沒有那樣打字。我現在編輯了這個問題來反映它是如何實際輸入的。

所以現在我的問題是:爲什麼要把__放在頂級方法的前面呢,還是好像呢?我明白這是用Python命名「私人事物」的慣例,因爲它在這種情況下不起作用,您會推薦什麼?

+0

凡'square'在相對文件結構中定義的? – kojiro

+0

無法重現。以前的代碼片段對我來說同樣適用於2.7和3.5版本。 –

+0

當我在同一個文件中定義了相同的函數時,我已經得到了這個,相隔幾行。使用Python 3.5 – Andrew

回答

7

您不應該在函數名前加兩個下劃線 - __ - 只要在類內的代碼中找到以兩個下劃線名稱爲前綴的名稱,Python編譯器就會執行名稱綁定操作。 - 因此,在編譯(到字節碼)時,您對__square的引用被轉換爲對不存在的_Foo_square的引用。

只需使用一個_就像在_square一樣,你不會有這個錯誤。

Python沒有像「私人」名稱這樣的事情。按照約定 - 僅限約定 - 不應從其他作用域的代碼調用或訪問以_爲前綴的函數或屬性。

爲了努力爲其他廣爲人知的OOP語言中存在的每個概念創建等價性,實際上提到雙下劃線前綴相當於這些語言中的「私有」變量。在舊文檔中這是一個常見的錯誤 - 最近的文章避免了這種錯誤。

雙下劃線前綴具有的行爲是不同的 - 有時它可以達到與private(而不是protected)屬性相同的目的:它在整個操作過程中將變量名稱轉換爲名稱整形Python的文檔。通常,這用於屬性名稱,並且它被轉換爲一個對容器類唯一的名稱,默認情況下它只能在它定義的類上訪問,而不在其子類中。這種轉換是確定性的,並有詳細記錄:一個下劃線,類名前面加上屬性名(包括兩個下劃線)。因此,Polygon類,將有一個__area屬性實際上有一個_Polygon__area在運行時 - 如果派生類class Square(Polygon):將試圖訪問其代碼的__area屬性,它實際上在運行時訪問_Square__area。 (但有可能讀取並通過在代碼編寫明確寫Square._Polygon__area__area

+2

今天我又學到了一些關於python的新東西。這裏記錄:https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references –