23

いくつかの属性を持つクラスがあるとします。これらの属性にアクセスするには、どのように (Pythonic-OOP の) 意味で最善ですか? のようにobj.attr?それとも get アクセサーを書きますか? そのようなものに受け入れられている命名スタイルは何ですか?

編集: 単一または二重の先頭のアンダースコアを使用して属性に名前を付けるベストプラクティスについて詳しく説明できますか? ほとんどのモジュールで、単一のアンダースコアが使用されていることがわかります。


この質問が既に尋ねられている場合 (そして、検索しても結果が得られなかったにもかかわらず、そのような予感がします)、それを指摘してください - そして私はこの質問を閉じます.

4

7 に答える 7

57

シングルおよびダブルのアンダースコアに関しては、どちらも「プライベート」の同じ概念を示しています。つまり、属性(メソッドまたは「通常の」データ属性など)がオブジェクトのパブリックAPIの一部ではないことがわかります。人々はそれに直接触れることは災害を招くことであることを知っているでしょう。

さらに、ダブルリーディングアンダースコア属性(シングルリーディングアンダースコア属性ではない)は、サブクラスまたは現在のクラス外の他の場所から誤ってアクセスする可能性を低くするために名前が変更されています。あなたはまだそれらにアクセスすることができますが、ささいなことではありません。例えば:

>>> class ClassA:
...     def __init__(self):
...         self._single = "Single"
...         self.__double = "Double"
...     def getSingle(self):
...         return self._single
...     def getDouble(self):
...         return self.__double
... 
>>> class ClassB(ClassA):
...     def getSingle_B(self):
...         return self._single
...     def getDouble_B(self):
...         return self.__double
... 
>>> a = ClassA()
>>> b = ClassB()

これで、以下によって作成された属性に簡単にアクセスa._singleb._singleて取得できます。_singleClassA

>>> a._single, b._single
('Single', 'Single')
>>> a.getSingle(), b.getSingle(), b.getSingle_B()
('Single', 'Single', 'Single')

ただし、またはインスタンスの__double属性に直接アクセスしようとしても機能しません。ab

>>> a.__double
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: ClassA instance has no attribute '__double'
>>> b.__double
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: ClassB instance has no attribute '__double'

そして、で定義されたメソッドClassAはそれを直接取得できますが(いずれかのインスタンスで呼び出された場合):

>>> a.getDouble(), b.getDouble()
('Double', 'Double')

で定義されたメソッドはClassBできません:

>>> b.getDouble_B()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in getDouble_B
AttributeError: ClassB instance has no attribute '_ClassB__double'

そして、そのエラーの中で、何が起こっているのかについてのヒントが得られます。属性名は、クラス内でアクセスされると、アクセスされ__doubleているクラスの名前を含むように名前が変更されます。にアクセスしようとすると、実際には、コンパイル時に、のアクセスに変わります。同様に。のアクセスにもなります。(のメソッドがに割り当てられ、簡潔にするためにコードに含まれていない場合、そのメソッドはに触れずに新しい属性を作成します。)この属性の他の保護はないため、次の場合でも直接アクセスできます。正しい名前を知っている:ClassAself.__doubleself._ClassA__doubleClassBClassB__doubleClassA__double

>>> a._ClassA__double, b._ClassA__double
('Double', 'Double')

では、なぜこれが問題なのですか?

この属性を処理するコードの動作を継承して変更したい場合は、いつでも問題になります。この二重アンダースコア属性に直接触れるすべてを再実装するか、クラス名を推測して名前を手動でマングルする必要があります。この二重アンダースコア属性が実際にメソッドである場合、問題はさらに悪化します。メソッドをオーバーライドするか、サブクラスでメソッドを呼び出すと、名前を手動で操作するか、メソッドを呼び出すすべてのコードを再実装して、二重アンダースコア名を使用しないようにします。 。属性に動的にアクセスすることは言うまでもなく、getattr():を使用して手動でマングルする必要もあります。

一方、属性は簡単に書き直されるだけなので、表面的な「保護」しか提供しません。コードは手動でマングリングすることで属性を取得できますが、コードはクラスの名前に依存し、コードをリファクタリングしたり、クラスの名前を変更したりするための努力が必要になります(同じユーザーが表示されたままになります)。名前、Pythonの一般的な方法)は、不必要にコードを壊してしまいます。また、Pythonをだまして、クラスに自分のクラスと同じ名前を付けることで、名前をマングリングすることもできます。マングルされた属性名にモジュール名が含まれていないことに注意してください。そして最後に、二重アンダースコア属性は、すべての属性リストと、表示されないすべての形式のイントロスペクションに引き続き表示されます。シングル)アンダースコア。

したがって、二重アンダースコアの名前を使用する場合は、非常に不便になる可能性があるため、非常に控えめに使用してください。またサブクラスが再実装、オーバーライド、または直接アクセスする可能性のあるメソッドやその他の名前には使用しないでください。また、二重のアンダースコアの名前マングリングは実際の保護を提供しないことを理解してください。結局、単一の先頭のアンダースコアを使用すると、同じように勝ち、(潜在的な、将来の)苦痛が少なくなります。単一の先頭の下線を使用します。

于 2008-10-03T09:37:51.120 に答える
23

一般的に受け入れられている方法は、次のように単純な属性を使用することです。

>>> class MyClass:
...     myAttribute = 0
... 
>>> c = MyClass()
>>> c.myAttribute 
0
>>> c.myAttribute = 1
>>> c.myAttribute
1

ゲッターとセッターを記述できるようにする必要がある場合は、「python クラス プロパティ」を探してください。Ryan Tomayko の Getters/Setter/Fuxors に関する記事は、開始するのに最適な場所です (少し長いですが)。

于 2008-10-03T06:35:37.007 に答える
8

編集:単一または二重の先頭の下線を使用して属性に名前を付けるベストプラクティスについて詳しく説明できますか?ほとんどのモジュールで、単一のアンダースコアが使用されていることがわかります。

単一のアンダースコアは、Pythonに特別なことを意味するものではありません。「何をしているのかを理解していない限り、おそらくこれにアクセスしたくない」と言うのがベストプラクティスです。ただし、二重アンダースコアを使用すると、Pythonが内部的に名前をマングルし、定義されているクラスからのみアクセスできるようになります。

二重の先頭と末尾の下線は__add__、+演算子を使用するときに呼び出されるような特別な関数を示します。

詳細については、PEP 8、特に「命名規則」セクションを参照してください。

于 2008-10-03T09:23:40.087 に答える
3

ほとんどは直接アクセスするだけで、get/set メソッドは必要ないと思います。

>>> class myclass:
...     x = 'hello'
...
>>>
>>> class_inst = myclass()
>>> class_inst.x
'hello'
>>> class_inst.x = 'world'
>>> class_inst.x
'world'

ところで、dir() 関数を使用して、インスタンスにアタッチされている属性/メソッドを確認できます。

>>> dir(class_inst)
['__doc__', '__module__', 'x']

先頭の 2 つのアンダーバー「__」は、属性または関数を非公開にするために使用されます。その他の規則については、PEP 08 を参照してください: http://www.python.org/dev/peps/pep-0008/

于 2008-10-03T06:24:01.590 に答える
1

属性をプロパティに変換するのは簡単で簡単なので、Python は最初からアクセサーを定義する必要はありません。鮮やかなデモンストレーションについては、以下を参照してください。

中毒からの回復

于 2008-10-03T06:26:39.477 に答える
0

Pythonでゲッター/セッターを実行する本当の意味はありません。とにかくものを保護することはできません。プロパティを取得/設定するときに追加のコードを実行する必要がある場合は、組み込みのproperty()を見てください(python -c'help(property )')

于 2008-10-03T06:43:09.500 に答える
-2

ゲッターとセッターを使用する人もいます。使用するコーディング スタイルに応じて、getSpam および seteggs という名前を付けることができます。ただし、属性を読み取り専用または割り当て専用にすることもできます。それはちょっとやりにくいです。1 つの方法は、

> __getattr__

> __setattr__

メソッド。

編集:

私の答えはまだ正しいですが、私が気づいたように、それは正しくありません。Python でアクセサーを作成するより良い方法があり、それほど厄介ではありません。

于 2008-10-03T06:29:22.043 に答える