2012-09-20 55 views
12

我知道雙下劃線對於Python類屬性/方法意味着什麼,但這是否意味着方法參數的某些內容?Python方法的雙下劃線*參數*

看起來你不能將以雙下劃線開頭的參數傳遞給方法。這很令人困惑,因爲你可以爲普通功能做到這一點。

考慮這個腳本:

def egg(__a=None): 
    return __a 

print "egg(1) =", 
print egg(1) 
print 


class Spam(object): 

    def egg(self, __a=None): 
     return __a 

print "Spam().egg(__a=1) =", 
print Spam().egg(__a=1) 

運行此腳本產量:

egg(1) = 1 

Spam().egg(__a=1) = 
Traceback (most recent call last): 
    File "/....py", line 15, in <module> 
    print Spam().egg(__a=1) 
TypeError: egg() got an unexpected keyword argument '__a' 

我與Python 2.7.2檢查這一點。


一些其他的例子

這工作:

def egg(self, __a): 
    return __a 


class Spam(object): 

    egg = egg 

Spam().egg(__a=1) 

這不:

class Spam(object): 

    def _egg(self, __a=None): 
     return __a 

    def egg(self, a): 
     return self._egg(__a=a) 

Spam().egg(1) 

回答

12

名稱重整適用於所有標識符與領先的雙下劃線,regardless of where they occur(第二次該部分最後一句):

此轉換與使用標識符的語法上下文無關。

這更簡單的實現和定義,並更一致。這可能看起來很愚蠢,但整個名稱是一個醜陋的小黑客IMHO;而且不管怎樣,除了屬性/方法之外,你不應該使用類似這樣的名稱。

Spam().egg(_Spam__a=1)以及Spam().egg(1),確實有效。但即使您可以使其工作,但領先的下劃線(其中任意數目)在參數名稱中都沒有位置。或者在任何局部變量(例外:_)中。

編輯:你似乎發現了一個沒有人考慮過的角落案例。這裏的文檔不精確,或者實現有缺陷。它看起來關鍵字參數名稱沒有被損壞。看看字節碼(Python的3.2):

>>> dis.dis(Spam.egg) 
    3   0 LOAD_FAST    0 (self) 
       3 LOAD_ATTR    0 (_egg) 
       6 LOAD_CONST    1 ('__a') # keyword argument not mangled 
       9 LOAD_FAST    1 (a) 
      12 CALL_FUNCTION   256 
      15 RETURN_VALUE 
>>> dis.dis(Spam._egg) 
    2   0 LOAD_FAST    1 (_Spam__a) # parameter mangled 
       3 RETURN_VALUE 

這可能是植根於一個事實,即關鍵字參數等同於傳遞一個字典(在這種情況下{'__a': 1}),它的鍵不會被任何錯位。但說實話,我只是把它稱爲一個醜陋的角落案件,在一個已經很醜的特例中繼續前進。這並不重要,因爲無論如何你都不應該使用這樣的標識符。

+0

如果它發生「無論它們發生在哪裏」,我希望最後一個例子(我加的)工作。我想我知道它爲什麼沒有;它應該在「類命名空間」或類似的東西(我不知道什麼是正確的詞),對嗎? – tkf

+0

我也期待這一點,我很驚訝。我想這是文檔或實現中的一個缺陷。我現在正在編輯添加我的發現。 – delnan

+0

我同意這不是優雅的參數,但考慮在函數中有'self .__ dict __。update(kwds)'之類的東西,但想要控制函數的行爲。我能想到的控制行爲的唯一有效參數名稱是以雙下劃線開始的。 – tkf

3

它被轉換到_Spam__a

In [20]: class Spam(object): 
    ....:  
    ....:   def egg(self, __a=None): 
    ....:    return __a 
    ....: 

In [21]: Spam.egg.__func__.__code__.co_varnames 
Out[21]: ('self', '_Spam__a') 
1

雙下劃線或Name Mangling在類上下文是一個專用標識符。在你的例子中試試dir(Spam.egg),你會發現參數__a現在是_Spam__egg

您現在可以使用:

Spam().egg(_Spam__a=1)