Pythonには、次のサンプルクラスがあります。
class Foo:
self._attr = 0
@property
def attr(self):
return self._attr
@attr.setter
def attr(self, value):
self._attr = value
@attr.deleter
def attr(self):
del self._attr
ご覧のとおり、単純な「プライベート」属性「_attr」とそれにアクセスするプロパティがあります。単純なプライベート属性を宣言する多くのコードがあり、そのようなすべての属性を宣言することは「KISS」の哲学を尊重していないと思います。
したがって、特定のgetter/setter/deleterが必要ない場合、すべての属性をパブリック属性として宣言しないのはなぜですか?
私の答えは:カプセル化(OOP)の原理がそうではないからです!
最善の方法は何ですか?
通常、Pythonコードは niform Access Principle に従うよう努めています。具体的には、受け入れられているアプローチは次のとおりです。
foo.set_x(0)
ではなく_foo.x = 0
_を許可します。@property
_を使用します。つまり、_foo.x = 0
_はfoo.set_x(0)
を呼び出すようになりました。このアプローチの主な利点は、呼び出し元がこれを行えることです。
_foo.x += 1
_
コードが実際に行っている場合でも:
_foo.set_x(foo.get_x() + 1)
_
最初のステートメントは無限に読みやすくなっています。ただし、プロパティを使用すると、2番目の方法で取得するアクセス制御を(最初に、または後で)追加できます。
また、単一の下線で始まるインスタンス変数は、慣習的にプライベートであることに注意してください。つまり、アンダースコアは、値がプライベートであるとみなすことを他の開発者に通知するものであり、それらを直接混乱させるべきではありません。ただし、言語には何もありません、それらを直接いじるのを防ぎます。
二重の先頭のアンダースコア(たとえば___x
_)を使用する場合、Pythonは名前の難読化を行います。変数は難読化された名前を介してクラスの外部からアクセス可能です。しかし、それは本当にプライベートではなく、単に...より不透明で、ダブルアンダースコアの使用に反対する有効な議論があります; 1つには、デバッグが難しくなる可能性があります。
「dunder」(二重アンダースコア、__
)プレフィックスは、アクセサーを介した場合を除き、属性へのアクセスを防ぎます。
class Foo():
def __init__(self):
self.__attr = 0
@property
def attr(self):
return self.__attr
@attr.setter
def attr(self, value):
self.__attr = value
@attr.deleter
def attr(self):
del self.__attr
いくつかの例:
>>> f = Foo()
>>> f.__attr # Not directly accessible.
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__attr'
>>> '__attr' in f.__dir__() # Not listed by __dir__()
False
>>> f.__getattribute__('__attr') # Not listed by __getattribute__()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__attr'
>>> f.attr # Accessible by implemented getter.
0
>>> f.attr = 'Presto' # Can be set by implemented setter.
>>> f.attr
'Presto'
>>> f.__attr = 'Tricky?' # Can we set it explicitly?
>>> f.attr # No. By doing that we have created a
'Presto' # new but unrelated attribute, same name.
簡単に言うと、OOPの原則は間違っています。なぜこれがフレームワークにつながる長い議論であり、おそらくこのサイトでは話題にならないでしょう。:-)
Pythonプライベート属性はありません。それらを保護することはできません。これは実際の問題ではありません。そうしないでください。簡単です!:)
次に質問があります:アンダースコアが先行するかどうか。そして、あなたがここに持っている例では、絶対にすべきではありません。 Pythonの先頭のアンダースコアは、何かが内部的であり、APIの一部ではないこと、およびそれを自分のリスクで使用する必要があることを示す規則です。これは明らかにここではありません、しかしそれは一般的で便利な慣例です。
Pythonにはpublic OR private属性がありません。すべての属性はすべてのコードにアクセスできます。
self.attr = 0 #Done
あなたのメソッドは_attrをプライベートにするものではなく、少し難読化されています。
このリンクを参照してください: https://docs.python.org/2/tutorial/classes.html
オブジェクトの内部からしかアクセスできない「プライベート」インスタンス変数は、Pythonには存在しません。ただし、ほとんどのPythonコード:アンダースコアで始まる名前(_spamなど)は、APIの非公開部分として扱われる必要があります。関数、メソッド、またはデータメンバー)実装の詳細と見なされ、予告なく変更される場合があります。
クラスプライベートメンバには有効なユースケースがあるため(つまり、サブクラスで定義された名前と名前の衝突を避けるため)、名前マングリングと呼ばれるこのようなメカニズムのサポートは制限されています。 __spam(少なくとも2つの先行アンダースコア、最大1つの後続アンダースコア)の形式の識別子は、_classname__spamにテキストで置き換えられます。classnameは、先頭のアンダースコアを削除した現在のクラス名です。このマングリングは、クラスの定義内で発生する限り、識別子の構文上の位置に関係なく行われます。
他の人が言ったように、Python=)のプライベート属性は単なる慣習です。属性がバインド、変更、または削除された場合の特別な処理には、property
構文の使用が必要です。 of Pythonは、通常の属性バインディングを使用することで開始できることです。たとえば、self.attr = 0
そして後日、attrの値を制限して0 <= attr <=100
、attr
をプロパティにし、メソッドを定義して、ユーザーコードを変更することなく、この条件が真であることを確認できます。
属性を非公開にするには、self.__attr
class Foo:
self.__attr = 0
@property
def attr(self):
return self._attr
@attr.setter
def attr(self, value):
self._attr = value
@attr.deleter
def attr(self):
del self._attr
Pythonでは、属性から特別な動作が必要な場合を除き、アクセサーメソッドの背後に非表示にする必要はありません。属性が内部使用専用の場合は、アンダースコアを前に付けます。
プロパティのいいところは、本当にクールなインターフェイスを提供してくれたことです。他のいくつかに基づいてプロパティを導出すると便利な場合があります(つまり、BMIは体重と身長によって定義されます)。もちろん、インターフェースのユーザーはこれを知る必要はありません。
Java ie。Way nice。:)のような明示的なゲッターとセッターを持つよりも、この方法が好きです。