web-dev-qa-db-ja.com

オブジェクト名の前のシングルおよびダブルのアンダースコアの意味は何ですか?

誰かがPythonでオブジェクトの名前の前に先行するアンダースコアを持つことの正確な意味を説明してもらえますか?また、一重と二重の先頭のアンダースコアの違いを説明してください。また、問題のオブジェクトが変数、関数、メソッドなどであっても、その意味は変わりませんか。

1115
Ram Rachum

シングルアンダースコア

クラス内で先頭にアンダースコアを付けた名前は、その属性またはメソッドが非公開であることを意図していることを他のプログラマに単に示すためのものです。ただし、名前自体に関して特別なことは何もされていません。

引用するには PEP-8

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

ダブルアンダースコア(ネームマングリング)

からPythonドキュメント

形式__spam(少なくとも2つの先行アンダースコア、最大1つの後続アンダースコア)のIDは、テキストで_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!'}
1010
Andrew Keeton

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

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

たとえば、FIFOとは異なるキューイング規則でスレッドセーフキューを作成するには、キューをインポートし、Queue.Queueをサブクラス化し、_get_putなどのメソッドをオーバーライドします。 「クライアントコード」はこれらの(「フック」)メソッドを呼び出すことはなく、putgetなどの(「組織化」)パブリックメソッドを呼び出します(これは テンプレートメソッド)として知られています デザインパターン-例えば here を参照してください。主題に関する私の話のビデオに基づく興味深いプレゼンテーションについて、転写産物の概要を追加しています)。

288
Alex Martelli

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

_foo:これは単なる慣習、プログラマは(それはPythonであらゆる手段)変数がプライベートであることを示すための方法です。

__foo:これは本当の意味を持つ:インタプリタは名前が別のクラスで同様の名前と重複しないことを保証するための方法として_classname__fooでこの名前を置き換えます。

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

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

268
Ned Batchelder

._variableは準専用で、慣例のためだけのものです

.__variableはしばしば誤って優先権があると見なされますが、実際の意味は - に誤って命名することです 偶然のアクセスを防ぐため[1]

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

必要に応じて、.__mangled変数にアクセスできます。二重のアンダースコアだけnamemangles、または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にアクセスすることで、隠し値にアクセスできます。

188
NickCSE

先頭に1つのアンダースコアを付けます。

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は "private"なので、アクセスしないでください。

先頭に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ガイド を参照してください。より魔法のような方法については、 this PDF を参照してください。

97
PythonDev

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

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

この場合、_()はテキストをロケールに基づいて適切な言語などに変換するローカライズ関数の別名です。たとえば、Sphinxがこれを実行します。インポートの中から見つけることができます。

from sphinx.locale import l_, _

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

15
Tim D

もし変数を本当に読み込み専用にしたいのなら、私見が一番良い方法は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が多少異なる質問をしたことを理解していますが、 'プライベート変数を設定する方法'を求める別の質問がこの質問と重複していることがわかったので、ここに追加情報を追加することを考えました。

7
Dev Maha

先頭に1つのアンダースコアは慣例です。名前が単一のアンダースコアで始まっていてもいなくても、インタプリタの観点と違いはありません。

二重の先頭と末尾のアンダースコアは、__init____bool__などの組み込みメソッドに使用されます。

末尾の対応するものなしの二重先行アンダースコアも規約ですが、クラスメソッドはインタプリタによって マングル になります。変数や基本関数名に違いはありません。

5
SilentGhost

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

しかし、例えば__double_underscore名はモジュール内で名前マングルされていません。 1つ(または複数)の下線で始まる名前は、モジュールから(モジュールのインポート*から)すべてインポートするとインポートされず、ヘルプ(module)にも表示されません。

3
u0b34a0f6ae

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

参照 https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references

3
aptro

これは、二重下線プロパティが継承クラスにどのように影響するかについての簡単な例です。次のように設定します。

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
Marc

非常に多くの人がRaymondの talk を参照しているので、私は彼が言ったことを書き留めることによってそれを少し簡単にするつもりです:

二重下線の意図はプライバシーについてではありませんでした。その意図は、これを正確にこのように使用することでした。

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

それは実際にはプライバシーの反対であり、それはすべて自由に関するものです。それはあなたのサブクラスが他のものを壊さずに任意の一つのメソッドを自由にオーバーライドできるようにします

perimeterのローカル参照をCircleに保存しないとします。現在、派生クラスTireは、perimeterに触れることなく、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を必要としません。

0
laike9m

_と__の事実を知るのはとても簡単です。他の答えはそれらをかなりよく表しています。用法は決定するのがはるかに難しいです。

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

_

関数が、例えばAPIのように公用ではないことを示すために使用されるべきです。これとインポートの制限により、c#のinternalのように動作します。

__

継承階層での名前の衝突を回避し、遅延結合を回避するために使用する必要があります。 C#でプライベートに似ています。

==>

何かが公に使用されるものではないことを示したいが、protected use _のように振る舞うべきです。何かが公に使用されるものではないことを示したいが、private use __のように振る舞うべきです。

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

問題は、クラスの作者が「この属性/メソッド名は非公開でなければならず、このクラス定義内からのみアクセス可能であるべきだ」と正当に考え、__private規則を使用することです。しかし後で、そのクラスのユーザーは合法的にその名前へのアクセスを必要とするサブクラスを作るかもしれません。そのため、スーパークラスを変更する必要があり(これは困難または不可能な場合もあります)、またはサブクラスのコードでは手動でマングル化された名前を使用する必要があります(最高でも醜く脆弱です)。

しかし、それに伴う問題は、メソッドをオーバーライドするときに警告するIDEがない場合、誤って基本クラスのメソッドをオーバーライドした場合、エラーを見つけるのにしばらく時間がかかることです。

0
Ini

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

意味:

some_variable - これは誰でも見ることができる一般公開です。

_some_variable - ►誰でもこれを見ることができることが公に公開されていますが、非公開であることを示すための規約です... warning Pythonでは強制されていません。

__some_varaible - ▶Pythonは変数名を_classname__some_varaible(AKA name mangling)に置き換えます。これは可視性を減らしたり隠したりしてプライベート変数のようにします。

ここで正直に言うと 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)
0
grepit