オブジェクト名の前の単一および二重の下線の意味は何ですか?


1292

Pythonでオブジェクト名の前にアンダースコアを付けることの正確な意味と、両者の違いを誰かが説明できますか?

また、問題のオブジェクトが変数、関数、メソッドなどであっても、その意味は同じですか?


2
別のスレッドからの素晴らしい短い答え:stackoverflow.com/a/8689983/911945
Anton Tarasenko

回答:


1156

単一下線

クラス内で先頭にアンダースコアが付いている名前は、属性またはメソッドがプライベートであることを意図していることを他のプログラマに示すためのものです。ただし、名前自体には特別な処理は行われません。

PEP-8を引用するには:

_single_leading_underscore:弱い「内部使用」インジケーター。たとえばfrom M import *、名前がアンダースコアで始まるオブジェクトはインポートされません。

二重下線(名前のマングリング)

Python docsから:

フォームの識別子__spam(先頭のアンダースコアが2つ、末尾のアンダースコアが最大1つ)は、テキストでに置き換えられます_classname__spam。ここで、classnameは、先頭のアンダースコアが削除された現在のクラス名です。このマングリングは、識別子の構文上の位置に関係なく行われるため、クラスプライベートインスタンスとクラス変数、メソッド、グローバルに格納された変数、さらにはインスタンスに格納された変数の定義に使用できます。他のクラスのインスタンスでこのクラスにプライベート。

そして同じページからの警告:

名前マングリングは、派生クラスで定義されたインスタンス変数やクラス外のコードでインスタンス変数をいじる必要なく、クラスに「プライベート」インスタンス変数とメソッドを定義する簡単な方法を提供することを目的としています。マングリングルールは主に事故を回避するように設計されていることに注意してください。決心した魂がプライベートと見なされる変数にアクセスまたは変更することは依然として可能です。

>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}

17
クラスにない2つのアンダースコアで宣言された変数名がある場合はどうなりますか?それは通常の変数ですよね?
Dhruv Ramani 2015

5
__変数名としてアンダースコアを2つ使用する意味は何ですか?様a, __ = foo()
AJ

104
この回答は、dunderscoreがインスタンス属性を「スーパープライベート」にするために使用されていると読者に信じさせるため、非常に誤解を招くものです。レイモンドヘッティンガーがここで説明したように、これは当てはまりません。レイモンドヘッティンガーは、メンバーをプライベートとしてマークするために誤って使用されていると明示的に述べていますが、プライベートとは反対に設計されています。
Markus Meskanen、2016年

13
@MarkusMeskanen同意しません。答えは、クラスプライベート変数およびメソッドのインスタンスを作成するためのdunderscoreの使用を明示的に示しています。dunderscoreはこれらのメソッドと変数をサブクラスで簡単に上書きできるように設計されていますが(パブリックにする)、dunderscoreを使用すると、そのクラス内で使用するプライベートインスタンスが保持されます。
arewm

6
@MarkusMeskanen:スーパークラスを壊さずに、サブクラスがスーパークラスと同じ名前を使用するのは自由です。つまり、スーパークラスのダンダー名はそれ自体にプライベートになります。
イーサンファーマン

311

これまでのところ優れた答えですが、いくつかのヒントがありません。単一の先行アンダースコアは、単なる規則ではありません。を使用しfrom foobar import *、モジュールfoobar__all__リストを定義していない場合、モジュールからインポートされた名前には、先行アンダースコアのある名前含まれません。このケースはかなりあいまいなコーナーなので、これはに慣習だとしましょう;-)。

先頭のアンダースコアの規則は、プライベート名だけでなく、C ++が保護されたものと呼ぶものにも広く使用されています。たとえば、サブクラスによって完全にオーバーライドされることを意図したメソッドの名前(以降、オーバーライドする必要があるものでも)それらの基本クラスraise NotImplementedError!-)は、多くの場合、そのクラス(またはサブクラス)のインスタンスを使用するコードに、メソッドが直接呼び出されることを意図していないことを示す単一の先行アンダースコア名です。

例えば、FIFOとは異なるキューイング規律とスレッドセーフなキューを作るために、1つの輸入キュー、Queue.Queueはサブクラス、およびそのようなメソッドをオーバーライド_getして_put、「クライアントコード」はこれらの(「フック」)メソッドを呼び出すのではなく、putand get(「組織化」)などのパブリックメソッドを呼び出します(これはテンプレートメソッドデザインパターンとして知られています。たとえば、ビデオに基づく興味深いプレゼンテーションについては、こちらを参照してください)主題の筆者の話の、筆記録の概要が追加されています)。

編集:講演の説明にあるビデオリンクが壊れています。あなたはここここに最初の2つのビデオを見つけることができます。


1
+を使用する_var_nameか使用しないかをどのように決定しますか?var_name__all__
内部石2017年

3
@endolith先頭のアンダースコアを使用して、コードの読者におそらくこれを使用しないように知らせます(たとえば、バージョン2.0または1.1で変更する可能性があるため)。__all__モジュールをfrom spam import *使いやすくしたいときはいつでも(インタラクティブなインタプリタを含む)明示的に使用します。ほとんどの場合、答えは両方です。
abarnert

@AlexMartelliこのインポートに関連するルールは、ドキュメントまたは他の場所で合法的に議論されていますか?
Vicrobot、2018

1
C ++の類推が好きです。まず、私が_ プライベートと呼ぶときは嫌いです。Pythonでは真にプライベートなものは何もないので、明らかに私は類推について話している。セマンティクスに飛び込むとき、Javaで保護されていることは「派生クラスおよび/または同じパッケージ内」を意味するため、_Javaの保護にを関連付けることができると私は言います。PEP8 _は、*インポートについて話すときの慣習ではなく、それを持っているということをすでにPEP8が教えているので、パッケージをモジュールで置き換えます。そして、クラス内の識別子について話すときは__、Javaのプライベートと間違いなく同等です。
Marius Mucenicu

2
まともな答えですが、それはまた、かなり自己宣伝です。
ハイブリッドWeb開発者

299

__foo__:これは単なる慣例であり、Pythonシステムがユーザー名と競合しない名前を使用する方法です。

_foo:これは単なる慣例であり、プログラマーが変数がプライベートであることを示すための方法です(Pythonでそれが意味するものは何でも)。

__foo:これには本当の意味があります。インタプリタは、この名前を_classname__foo別のクラスの類似の名前と重複しないようにするために、この名前をに置き換えます。

Pythonの世界では、他の形式のアンダースコアは意味を持ちません。

これらの規則では、クラス、変数、グローバルなどに違いはありません。


6
ちょうど出会い__foo、好奇心が強い。他のクラスと同様のメソッド名とどのようにオーバーラップできますか?私はあなたがまだそれにアクセスする必要があることを意味しますinstance.__foo()(インタープリターによって名前が変更されなかった場合)、そうですか?
Bibhas Debnath 2013

81
この男は、from module import *アンダースコアが前に付いたオブジェクトをインポートしないと述べています。したがって、_fooは単なる規則ではありません。
dotancohen 2013年

4
@Bibhas:クラスの場合B、サブクラスのクラスはA、との両方を実装foo()し、B.foo()上書きされます.foo()から継承されましたA。を介した場合を除いて、のインスタンスはBにのみアクセスできます。B.foo()super(B).foo()
naught101

3
以下のために__dunder__、それは(参照おそらく、もう少しいくつかのケースでは、単に命名規則よりですので、名前、暗黙の呼び出しは、インスタンス辞書をスキップする特殊な方法で検索データモデル内のセクションを)。
WIM

206

._variable セミプライベートであり、慣例にすぎません

.__variable多くの場合、誤ってスーパープライベートと見なされますが、実際の意味は、偶発的なアクセス防ぐために名前を変更することです[1]

.__variable__ 通常、組み込みのメソッドまたは変数用に予約されています

.__mangled必要に応じて変数にアクセスできます。二重下線は、変数を次のような名前に変更するか、名前を変更するだけですinstance._className__mangled

例:

class Test(object):
    def __init__(self):
        self.__a = 'a'
        self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t._bは、慣例によってのみ隠されているため、アクセス可能です。

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

t .__ aは、ネームマングリングのために存在しないため、見つかりません。

>>> t._Test__a
'a'

instance._className__variable二重下線名だけでなく、アクセスすることで、非表示の値にアクセスできます


しかし、どのように「__aは」クラス変数だった場合について、その後、あなたはPythonのドキュメントからの命令でも、それをアクセスすることはできません...
Vitaliy Terziev

継承に関する二重下線の例で回答を更新できますか?
可変

116

最初に単一の下線:

Pythonには実際のプライベートメソッドはありません。代わりに、メソッドまたは属性名の先頭に下線が1つあることは、このメソッドはAPIの一部ではないため、このメソッドにアクセスしてはならないことを意味します。

class BaseForm(StrAndUnicode):

    def _get_errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    errors = property(_get_errors)

(このコードスニペットは、djangoソースコードから取得されました:django / forms / forms.py)。このコードでerrorsは、はパブリックプロパティですが、このプロパティが呼び出すメソッド_get_errorsは「プライベート」なので、アクセスしないでください。

最初に2つのアンダースコア:

これは多くの混乱を引き起こします。プライベートメソッドの作成には使用しないでください。これは、メソッドがサブクラスによってオーバーライドされたり、誤ってアクセスされたりしないようにするために使用する必要があります。例を見てみましょう:

class A(object):
    def __test(self):
        print "I'm a test method in class A"

    def test(self):
        self.__test()

a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!

出力:

$ python test.py
I'm test method in class A
I'm test method in class A

次に、サブクラスBを作成し、__ testメソッドをカスタマイズします。

class B(A):
    def __test(self):
        print "I'm test method in class B"

b = B()
b.test()

出力は...になります。

$ python test.py
I'm test method in class A

これまで見てきたように、A.test()はB .__ test()メソッドを呼び出しませんでした。しかし、実際には、これは__の正しい動作です。__test()と呼ばれる2つのメソッドは、_A__test()および_B__test()に自動的に名前変更(マングル)されるため、誤ってオーバーライドされることはありません。__で始まるメソッドを作成するときは、誰もそのメソッドをオーバーライドできないようにする必要がなく、独自のクラス内からのみアクセスすることを意図しています。

最初と最後に2つのアンダースコア:

のようなメソッドを見つけたら__this__、呼び出さないでください。これはpythonが呼び出すことを意図したメソッドであり、あなたではありません。見てみましょう:

>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11

>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

これらの魔法のメソッドを呼び出す演算子またはネイティブ関数が常に存在します。場合によっては、特定の状況でpythonが呼び出すフックにすぎません。たとえば、インスタンスを作成するため__init__()__new__()が呼び出された後にオブジェクトが作成されたときに呼び出されます...

例を挙げましょう...

class FalseCalculator(object):

    def __init__(self, number):
        self.number = number

    def __add__(self, number):
        return self.number - number

    def __sub__(self, number):
        return self.number + number

number = FalseCalculator(20)
print number + 10      # 10
print number - 20      # 40

詳細については、PEP-8ガイドを参照してください。その他の魔法の方法については、このPDFを参照してください。


1
この回答を自分で編集した後、私はstackoverflow.com/a/8689983/1048186
Josiah Yoder

「見てきたように、A.test()はB .__ test()メソッドを呼び出さなかった」とはどういう意味ですか?A.test()をどこで呼び出しましたか?
可変

18

時々あなたは次のように先行するアンダースコアを持つタプルのように見えるものを持っています

def foo(bar):
    return _('my_' + bar)

この場合、何が起こっているのかといえば、_()は、テキストを操作してロケールに基づいて適切な言語などにローカライズするローカリゼーション関数のエイリアスです。たとえば、Sphinxはこれを行い、インポートの中から見つけることができます

from sphinx.locale import l_, _

sphinx.localeでは、_()がローカライズ関数のエイリアスとして割り当てられています。


11

レイモンドの講演については非常に多くの人が言及しているので、彼が言ったことを書き留めて少し簡単にします。

二重下線の意図はプライバシーについてではありませんでした。まさにこのように使うつもりでした

class Circle(object):

    def __init__(self, radius):
        self.radius = radius

    def area(self):
        p = self.__perimeter()
        r = p / math.pi / 2.0
        return math.pi * r ** 2.0

    def perimeter(self):
        return 2.0 * math.pi * self.radius

    __perimeter = perimeter  # local reference


class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

それは実際にはプライバシーの反対であり、それは自由についてです。他のクラスを壊すことなく、任意の1つのメソッドをオーバーライドするために、サブクラスを自由にします

のローカル参照を保持しないとperimeterCircleます。現在、派生クラスTireperimeter、に触れることなく、の実装をオーバーライドしていますarea。を呼び出すTire(5).area()と、理論上はまだCircle.perimeter計算に使用されているはずですが、実際にTire.perimeterはを使用していますが、これは意図された動作ではありません。そのため、Circleでローカル参照が必要です。

しかし、なぜ__perimeter代わりに_perimeter?そのため_perimeter、まだオーバーライドする派生クラスにチャンスを与えます:

class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

    _perimeter = perimeter

二重下線には名前のマングリングがあるため、親クラスのローカル参照が派生クラスでオーバーライドされる可能性はほとんどありません。したがって、「サブクラスを自由にして、他のメソッドを壊すことなく任意のメソッドをオーバーライドできます」。

クラスが継承されない場合、またはメソッドのオーバーライドによって何も壊れない場合は、単に必要ありません__double_leading_underscore


1
ありがとう、スライドが適切に表示されなかったので、コードが失敗する理由がわかりませんでした。
cgte

8

変数を本当に読み取り専用にしたい場合、IMHOはgetterのみを渡してproperty()を使用するのが最善の方法です。property()を使用すると、データを完全に制御できます。

class PrivateVarC(object):

    def get_x(self):
        pass

    def set_x(self, val):
        pass

    rwvar = property(get_p, set_p)  

    ronly = property(get_p) 

OPが少し異なる質問をしたことは理解していますが、「プライベート変数を設定する方法」を尋ねる別の質問があり、これと重複しているため、この追加情報をここに追加することを考えました。


8

https://dbader.org/blog/meaning-of-underscores-in-pythonへのアクセス

  • Single Leading Underscore(_var):名前を示す命名規則は、内部使用を目的としています。通常、Pythonインタープリターによって強制されず(ワイルドカードのインポートを除く)、プログラマーのみへのヒントとして意図されています。
  • 単一の末尾のアンダースコア(var_):Pythonキーワードとの名前の競合を回避するために慣例により使用されます。
  • Double Leading Underscore(__ var):クラスコンテキストで使用すると、名前のマングリングをトリガーします。Pythonインタープリターによって実施されます。
  • 二重の先頭と末尾の下線(__var__):Python言語で定義された特別なメソッドを示します。独自の属性には、この命名規則を使用しないでください。
  • 単一下線(_):一時的または重要でない変数の名前として使用されることがあります(「ドントケア」)。また:Python REPLの最後の式の結果。

5

素晴らしい答えとすべてが正しいです。私は、簡単な定義/意味とともに簡単な例を提供しました。

意味:

some_variable--►誰でもこれを見ることができるパブリックです。

_some_variable--►誰でもこれを見ることができるのはパブリックですが、プライベートであることを示すのは慣習です... 警告 Pythonでは強制は行われません。

__some_varaible--►Pythonは変数名を_classname__some_varaible(別名名前変換)に置き換え、可視性を低減/非表示にし、プライベート変数のようにします。

正直に言うと、Pythonのドキュメントによると

「オブジェクトの内部以外からアクセスできない「プライベート」インスタンス変数は、Pythonには存在しません。」

例:

class A():
    here="abc"
    _here="_abc"
    __here="__abc"


aObject=A()
print(aObject.here) 
print(aObject._here)
# now if we try to print __here then it will fail because it's not public variable 
#print(aObject.__here)

_ _some_varaible - .... そしてそれは/非表示にそれの可視性を低減し、よりプライベート変数のようになります。いいえ、名前のマングリングがポイントであり、メソッドを隠しません。
AMC

4

単一の先行アンダースコアは規則です。名前が単一の下線で始まるかどうかは、インタープリターの観点からの違いはありません。

二重先頭と末尾の下線は、次のような組み込みの方法に使用される__init____bool__など

後続の対応なしの二重先行アンダースコアも慣例ですが、クラスメソッドはインタープリターによって壊されます。変数または基本的な関数名の場合、違いはありません。


3

あなたの質問はいいです、それは方法についてだけではありません。モジュール内の関数とオブジェクトには通常、1つのアンダースコアが前に付き、2つ前に付けることができます。

ただし、たとえば、__ double_underscoreの名前は、モジュール内では名前がマングルされません。1つ(または複数)のアンダースコアで始まる名前は、モジュールからすべてインポートした場合(モジュールインポート*から)インポートされず、名前もヘルプ(モジュール)に表示されません。


1
さらに、1つ以上のアンダースコアで始まり、2つ以上のアンダースコアが続く名前は、他の名前と同様に動作します。
Bentley4

3

以下は、2つのアンダースコアプロパティが継承されたクラスにどのように影響するかを示す簡単な例です。したがって、次の設定で:

class parent(object):
    __default = "parent"
    def __init__(self, name=None):
        self.default = name or self.__default

    @property
    def default(self):
        return self.__default

    @default.setter
    def default(self, value):
        self.__default = value


class child(parent):
    __default = "child"

その後、python REPLで子インスタンスを作成すると、以下が表示されます

child_a = child()
child_a.default            # 'parent'
child_a._child__default    # 'child'
child_a._parent__default   # 'parent'

child_b = child("orphan")
## this will show 
child_b.default            # 'orphan'
child_a._child__default    # 'child'
child_a._parent__default   # 'orphan'

これは一部の人には明白かもしれませんが、はるかに複雑な環境で油断しました


3

オブジェクト内以外からアクセスできない「プライベート」インスタンス変数は、Pythonには存在しません。ただし、ほとんどのPythonコードが従う規則があります。アンダースコアで始まる名前(_spamなど)は、APIの非公開部分として処理する必要があります(関数、メソッド、データメンバーのいずれであっても) 。これは実装の詳細と見なされ、予告なく変更されることがあります。

リファレンス https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references


1
_は、たとえばc#の内部に、プライベートに似ています。ダブルアンダースコアはプライベートに似ていますが、アンダースコアはプライベートです。
Ini

2

_および__の事実を取得するのは非常に簡単です。他の回答はそれらをかなりよく表現しています。使用法を決定することははるかに困難です。

これは私がそれを見る方法です:

_

たとえばAPIのように、関数がパブリックで使用されないことを示すために使用する必要があります。これとインポート制限によりinternal、C#と同様に動作します。

__

継承階層での名前の衝突を回避し、遅延バインディングを回避するために使用する必要があります。c#のprivateとよく似ています。

==>

何かが公共の用途ではないことを示したいが、それはprotecteduseのように振る舞うべきである場合_。何かが公共の用途ではないことを示したいが、それはprivateuseのように振る舞うべきである場合__

これも私がとても好きな引用です:

問題は、クラスの作成者が「この属性/メソッド名はプライベートであり、このクラス定義内からのみアクセス可能である」と正当に考え、__ private規則を使用することです。しかし後で、そのクラスのユーザーは、その名前へのアクセスを正当に必要とするサブクラスを作成する可能性があります。したがって、スーパークラスを変更する必要があるか(困難または不可能かもしれません)、またはサブクラスコードで手動でマングルされた名前を使用する必要があります(これは醜くて壊れやすいだけです)。

しかし、それに関する問題は、メソッドをオーバーライドするときに警告するIDEがない場合、誤ってベースクラスからメソッドをオーバーライドした場合、エラーを見つけるのに時間がかかる可能性があるというのが私の意見です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.