13

Python クラスの属性/メソッドに対する 2 つのアンダースコアの意味は知っていますが、メソッドの引数に対しては何か意味がありますか?

二重アンダースコアで始まる引数をメソッドに渡すことはできないようです。通常の関数でそれを行うことができるため、混乱します。

次のスクリプトを検討してください。

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)
4

3 に答える 3

13

名前マングリングは、それらがどこで発生するかに関係なく、先頭に二重のアンダースコアがあるすべての識別子に適用されます(そのセクションの最後から 2 番目の文)。

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

これは、実装と定義がより簡単で、より一貫性があります。ばかげているように思えるかもしれませんが、名前のマングリング取引全体が醜い小さなハックです。とにかく、属性/メソッド以外にはそのような名前を使用することは期待されていません。

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

これは、キーワード引数が dict (この場合は{'__a': 1}) を渡すことと同等であり、そのキーもマングルされないという事実に根ざしている可能性があります。しかし正直なところ、私はそれをすでに醜い特別なケースの中の醜いコーナーケースと呼んで先に進みたいと思います。とにかくそのような識別子を使用するべきではないので、それは重要ではありません。

于 2012-09-20T17:43:59.490 に答える
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')
于 2012-09-20T17:44:23.510 に答える
1

クラス コンテキストでの二重アンダースコアまたは名前マングリングは、プライベート識別子です。あなたの例で dir(Spam.egg) を試してみると、パラメーター __a が now であることがわかります_Spam__egg

以下を使用できるようになりました。

Spam().egg(_Spam__a=1)
于 2012-09-20T17:51:56.187 に答える