2012-09-20 8 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(に適用されますその部分の最後の文):

この変換は、識別子が使用されている構文的コンテキストとは無関係です。

これは実装して定義しやすく、より一貫しています。それは馬鹿に見えるかもしれないが、全体の名前mangling取引は、醜い小さなハック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

を、私は最後の例(私は追加1)が動作します期待しています。私はなぜそれがないのか知っていると思います。それは "クラスネームスペース"かそのようなものでなければなりません(私はそれに対して正しい言葉が何か分かりません)、そうですか? – 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) 
関連する問題