Pythonでオブジェクト名の前にアンダースコアを付けることの正確な意味と、両者の違いを誰かが説明できますか?
また、問題のオブジェクトが変数、関数、メソッドなどであっても、その意味は同じですか?
Pythonでオブジェクト名の前にアンダースコアを付けることの正確な意味と、両者の違いを誰かが説明できますか?
また、問題のオブジェクトが変数、関数、メソッドなどであっても、その意味は同じですか?
回答:
クラス内で先頭にアンダースコアが付いている名前は、属性またはメソッドがプライベートであることを意図していることを他のプログラマに示すためのものです。ただし、名前自体には特別な処理は行われません。
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!'}
__
変数名としてアンダースコアを2つ使用する意味は何ですか?様a, __ = foo()
これまでのところ優れた答えですが、いくつかのヒントがありません。単一の先行アンダースコアは、単なる規則ではありません。を使用しfrom foobar import *
、モジュールfoobar
が__all__
リストを定義していない場合、モジュールからインポートされた名前には、先行アンダースコアのある名前は含まれません。このケースはかなりあいまいなコーナーなので、これは主に慣習だとしましょう;-)。
先頭のアンダースコアの規則は、プライベート名だけでなく、C ++が保護されたものと呼ぶものにも広く使用されています。たとえば、サブクラスによって完全にオーバーライドされることを意図したメソッドの名前(以降、オーバーライドする必要があるものでも)それらの基本クラスraise NotImplementedError
!-)は、多くの場合、そのクラス(またはサブクラス)のインスタンスを使用するコードに、メソッドが直接呼び出されることを意図していないことを示す単一の先行アンダースコア名です。
例えば、FIFOとは異なるキューイング規律とスレッドセーフなキューを作るために、1つの輸入キュー、Queue.Queueはサブクラス、およびそのようなメソッドをオーバーライド_get
して_put
、「クライアントコード」はこれらの(「フック」)メソッドを呼び出すのではなく、put
and get
(「組織化」)などのパブリックメソッドを呼び出します(これはテンプレートメソッドデザインパターンとして知られています。たとえば、ビデオに基づく興味深いプレゼンテーションについては、こちらを参照してください)主題の筆者の話の、筆記録の概要が追加されています)。
_var_name
か使用しないかをどのように決定しますか?var_name
__all__
__all__
モジュールをfrom spam import *
使いやすくしたいときはいつでも(インタラクティブなインタプリタを含む)明示的に使用します。ほとんどの場合、答えは両方です。
_
プライベートと呼ぶときは嫌いです。Pythonでは真にプライベートなものは何もないので、明らかに私は類推について話している。セマンティクスに飛び込むとき、Javaで保護されていることは「派生クラスおよび/または同じパッケージ内」を意味するため、_
Javaの保護にを関連付けることができると私は言います。PEP8 _
は、*
インポートについて話すときの慣習ではなく、それを持っているということをすでにPEP8が教えているので、パッケージをモジュールで置き換えます。そして、クラス内の識別子について話すときは__
、Javaのプライベートと間違いなく同等です。
__foo__
:これは単なる慣例であり、Pythonシステムがユーザー名と競合しない名前を使用する方法です。
_foo
:これは単なる慣例であり、プログラマーが変数がプライベートであることを示すための方法です(Pythonでそれが意味するものは何でも)。
__foo
:これには本当の意味があります。インタプリタは、この名前を_classname__foo
別のクラスの類似の名前と重複しないようにするために、この名前をに置き換えます。
Pythonの世界では、他の形式のアンダースコアは意味を持ちません。
これらの規則では、クラス、変数、グローバルなどに違いはありません。
__foo
、好奇心が強い。他のクラスと同様のメソッド名とどのようにオーバーラップできますか?私はあなたがまだそれにアクセスする必要があることを意味しますinstance.__foo()
(インタープリターによって名前が変更されなかった場合)、そうですか?
B
、サブクラスのクラスはA
、との両方を実装foo()
し、B.foo()
上書きされます.foo()
から継承されましたA
。を介した場合を除いて、のインスタンスはB
にのみアクセスできます。B.foo()
super(B).foo()
._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
二重下線名だけでなく、アクセスすることで、非表示の値にアクセスできます
最初に単一の下線:
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
レイモンドの講演については非常に多くの人が言及しているので、彼が言ったことを書き留めて少し簡単にします。
二重下線の意図はプライバシーについてではありませんでした。まさにこのように使うつもりでした
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つのメソッドをオーバーライドするために、サブクラスを自由にします。
のローカル参照を保持しないと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
。
変数を本当に読み取り専用にしたい場合、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が少し異なる質問をしたことは理解していますが、「プライベート変数を設定する方法」を尋ねる別の質問があり、これと重複しているため、この追加情報をここに追加することを考えました。
https://dbader.org/blog/meaning-of-underscores-in-pythonへのアクセス
素晴らしい答えとすべてが正しいです。私は、簡単な定義/意味とともに簡単な例を提供しました。
意味:
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)
あなたの質問はいいです、それは方法についてだけではありません。モジュール内の関数とオブジェクトには通常、1つのアンダースコアが前に付き、2つ前に付けることができます。
ただし、たとえば、__ double_underscoreの名前は、モジュール内では名前がマングルされません。1つ(または複数)のアンダースコアで始まる名前は、モジュールからすべてインポートした場合(モジュールインポート*から)インポートされず、名前もヘルプ(モジュール)に表示されません。
以下は、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'
これは一部の人には明白かもしれませんが、はるかに複雑な環境で油断しました
オブジェクト内以外からアクセスできない「プライベート」インスタンス変数は、Pythonには存在しません。ただし、ほとんどのPythonコードが従う規則があります。アンダースコアで始まる名前(_spamなど)は、APIの非公開部分として処理する必要があります(関数、メソッド、データメンバーのいずれであっても) 。これは実装の詳細と見なされ、予告なく変更されることがあります。
リファレンス https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
_および__の事実を取得するのは非常に簡単です。他の回答はそれらをかなりよく表現しています。使用法を決定することははるかに困難です。
これは私がそれを見る方法です:
_
たとえばAPIのように、関数がパブリックで使用されないことを示すために使用する必要があります。これとインポート制限によりinternal
、C#と同様に動作します。
__
継承階層での名前の衝突を回避し、遅延バインディングを回避するために使用する必要があります。c#のprivateとよく似ています。
==>
何かが公共の用途ではないことを示したいが、それはprotected
useのように振る舞うべきである場合_
。何かが公共の用途ではないことを示したいが、それはprivate
useのように振る舞うべきである場合__
。
これも私がとても好きな引用です:
問題は、クラスの作成者が「この属性/メソッド名はプライベートであり、このクラス定義内からのみアクセス可能である」と正当に考え、__ private規則を使用することです。しかし後で、そのクラスのユーザーは、その名前へのアクセスを正当に必要とするサブクラスを作成する可能性があります。したがって、スーパークラスを変更する必要があるか(困難または不可能かもしれません)、またはサブクラスコードで手動でマングルされた名前を使用する必要があります(これは醜くて壊れやすいだけです)。
しかし、それに関する問題は、メソッドをオーバーライドするときに警告するIDEがない場合、誤ってベースクラスからメソッドをオーバーライドした場合、エラーを見つけるのに時間がかかる可能性があるというのが私の意見です。