1591

Pythonでオブジェクト名の前に単一および二重の先頭の下線を付けることの正確な意味と、両方の違いを誰かが説明できますか?

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

4

17 に答える 17

1395

単一のアンダースコア

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

PEP-8を引用するには:

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

ダブルアンダースコア(名前マングリング)

Pythonドキュメントから:

フォームの識別子__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!'}
于 2009-08-19T17:15:53.427 に答える
395

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

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

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

Pythonの世界では、他の形式のアンダースコアには意味がありません。

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

于 2009-08-19T17:21:29.873 に答える
355

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

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

たとえば、FIFOとは異なるキューイング規律を持つスレッドセーフキューを作成するには、Queueをインポートし、Queue.Queueをサブクラス化し、およびなどのメソッドをオーバーライドし_getます_put。「クライアントコード」はこれらの(「フック」)メソッドを呼び出すことはありませんが、putand get(これはテンプレートメソッドデザインパターンとして知られています-ビデオに基づく興味深いプレゼンテーションについては、ここを参照してください)などの(「整理」)パブリックメソッドを呼び出しますトランスクリプトの概要を追加した、このテーマに関する私の話の)。

編集:講演の説明のビデオリンクが壊れています。最初の2つのビデオはここここにあります。

于 2009-08-19T17:52:36.190 に答える
233

._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ことで、非表示の値にアクセスできます

于 2012-09-27T20:56:44.287 に答える
144

最初の単一の下線:

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を参照してください。

于 2014-12-15T10:10:20.990 に答える
55

Pythonのアンダースコアの意味によると

  • 単一の先頭の下線(_var:名前を示す命名規則は内部使用を目的としています。通常、Pythonインタープリターによって強制されることはなく(ワイルドカードのインポートを除く)、プログラマーへのヒントとしてのみ使用されます。
  • シングルトレーリングアンダースコア(var_:Pythonキーワードとの名前の競合を回避するために、慣例により使用されます。
  • Double Leading Underscore(__var:クラスコンテキストで使用される場合、名前マングリングをトリガーします。Pythonインタープリターによって強制されます。
  • Double Leading and Trailing Underscore(__var__:Python言語で定義された特別なメソッドを示します。独自の属性にこの命名スキームを使用することは避けてください。
  • シングルアンダースコア(_:一時的または重要でない変数の名前として使用されることがあります(「ドントケア」)。また:PythonREPLの最後の式の結果。
于 2019-11-27T08:45:06.263 に答える
19

場合によっては、次のように先頭にアンダースコアが付いたタプルのように見えるものがあります。

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

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

from sphinx.locale import l_, _

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

于 2012-01-11T16:28:22.907 に答える
16

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

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

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

しかし、なぜ__perimeterではなく_perimeter_perimeterそれでも派生クラスにオーバーライドする機会を与えるため:

class Tire(Circle):

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

    _perimeter = perimeter

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

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

于 2018-10-20T08:10:44.960 に答える
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が少し違う質問をしたことは理解していますが、これと重複する「プライベート変数の設定方法」を尋ねる別の質問を見つけたので、ここにこの追加情報を追加することを考えました。

于 2013-04-15T01:58:14.233 に答える
8
  • _var:Pythonで先頭に単一の下線が付いている変数は古典的な変数であり、コードを使用して他の人にこの変数を内部使用のために予約する必要があることを通知することを目的としています。__all__これらは、従来の変数とは1つの点で異なります。定義されているオブジェクト/モジュールのワイルドカードインポートを実行する場合はインポートされません(変数を定義する場合の例外)。例えば:

    # foo.py
    
    var = "var"
    _var = "_var"
    
    # bar.py
    
    from foo import *
    
    print(dir())  # list of defined objects, contains 'var' but not '_var'
    print(var)    # var
    print(_var)   # NameError: name '_var' is not defined
    
  • _:単一のアンダースコアは、先頭の単一のアンダースコア変数の特殊なケースです。慣例により、後でアクセスすることを意図していない値を格納するために、ごみ変数として使用されます。また、ワイルドカードインポートではインポートされません。例:このforループは「クラスで話してはいけない」を10回出力し、_変数にアクセスする必要はありません。

    for _ in range(10):
        print("I must not talk in class")
    
  • __var:2つの先頭のアンダースコア変数(少なくとも2つの先頭のアンダースコア、最大で1つの末尾のアンダースコア)。クラス属性(変数とメソッド)として使用される場合、これらの変数は名前マングリングの対象になります。クラスの外部では、Pythonは属性の名前をに変更します_<Class_name>__<attribute_name>。例:

    class MyClass:
        __an_attribute = "attribute_value"
    
    my_class = MyClass()
    print(my_class._MyClass__an_attribute)  # "attribute_value"
    print(my_class.__an_attribute)  # AttributeError: 'MyClass' object has no attribute '__an_attribute'
    

    クラス外の変数として使用される場合、それらは単一の先頭のアンダースコア変数のように動作します。

  • __var__:先頭と末尾のアンダースコア変数が2つ(少なくとも2つの先頭と末尾のアンダースコア)。ダンダーとも呼ばれます。この命名規則は、Pythonが変数を内部的に定義するために使用されます。Pythonの更新で発生する可能性のある名前の競合を防ぐために、この規則の使用は避けてください。Dunder変数は、単一の先頭のアンダースコア変数のように動作します。クラス内で使用する場合、名前マングリングの対象にはなりませんが、ワイルドカードインポートではインポートされません。

于 2021-01-06T14:12:54.847 に答える
6

単一の先頭の下線は慣例です。名前が単一の下線で始まるかどうかにかかわらず、インタプリタの観点との違いはありません。

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

末尾に対応するものがない二重の先頭の下線も慣例ですが、クラスメソッドはインタプリタによって壊されます。変数または基本関数名の場合、違いはありません。

于 2009-08-19T17:17:11.707 に答える
6

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

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'

これは一部の人には明らかかもしれませんが、はるかに複雑な環境で私を不意を突かれた

于 2014-08-22T19:15:48.357 に答える
6

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

意味:

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)
于 2019-01-21T22:23:39.263 に答える
3

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

ただし、たとえば、__ double_underscore名は、モジュール内で名前が変更されていません。モジュールから(module import *から)すべてをインポートした場合、1つ(または複数)の下線で始まる名前はインポートされず、help(module)にも名前が表示されません。

于 2009-08-19T17:31:04.347 に答える
3

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

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

于 2015-02-07T17:57:10.620 に答える
1

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

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

_

関数が、たとえばAPIのように公開されていないことを示すために使用する必要があります。internalこれとインポート制限により、c#の場合とほとんど同じように動作します。

__

継承のhirarchyでの名前の衝突を回避し、レイトバインディングを回避するために使用する必要があります。C#のプライベートによく似ています。

==>

何かが公用ではないことを示したいが、それはprotected使用のように機能する必要がある場合_。何かが公用ではないことを示したいが、それはprivate使用のように機能する必要がある場合__

これは私がとても好きな引用でもあります:

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

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

于 2017-11-04T17:46:10.817 に答える
0

メソッドの場合、二重アンダースコアを使用して、次のパターンでプライベートな「メソッド」を隠すことができます。

# Private methods of MyClass
def _MyClass__do_something(obj:'MyClass'):
    print('_MyClass__do_something() called. type(obj) = {}'.format(type(obj)))

class MyClass():
    def __init__(self):
        __do_something(self)

mc = MyClass()

出力:

_MyClass__do_something() called. type(obj) = <class '__main__.MyClass'>

今日、クラスメソッドに二重アンダースコアを使用しようとしたときにこれに遭遇し、NameError: name '_<class><method>' is not definedエラーが発生しました。

于 2020-12-22T20:29:36.913 に答える