web-dev-qa-db-ja.com

Pythonはクラス内に「プライベート」変数を持っていますか?

私はJavaの世界から来ていて、Bruce Eckelsの Python 3パターン、レシピ、熟語を読んでいます

クラスについて読みながら、Pythonではインスタンス変数を宣言する必要はないと言い続けています。あなたはそれらをコンストラクタの中で使うだけです、そしてブーム、彼らはそこにいます。

だから、例えば:

class Simple:
    def __init__(self, s):
        print("inside the simple constructor")
        self.s = s

    def show(self):
        print(self.s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

そうであれば、クラスSimpleのどのオブジェクトでも、クラス外の変数sの値を変更することができます。

例えば:

if __== "__main__":
    x = Simple("constructor argument")
    x.s = "test15" # this changes the value
    x.show()
    x.showMsg("A message")

Javaでは、public/private/protected変数について教えられました。これらのキーワードは、クラス外の誰にもアクセスできないクラス内の変数が必要な場合があるため、意味があります。

なぜPythonではこれが不要なのですか?

482
Omnipresent

文化的です。 Pythonでは、他のクラスのインスタンスやクラス変数には書き込みません。 Javaでは、really want to-結局、同じことをすることを妨げるものは何もありません-結局、同じ効果を達成するために常にクラス自体のソースを編集できます。 Pythonは、セキュリティのふりをして、プログラマーが責任を持つことを奨励します。実際には、これは非常にうまく機能します。

何らかの理由でプライベート変数をエミュレートする場合は、 PEP 8__プレフィックスをいつでも使用できます。 Pythonは、__fooのような変数の名前をマングルし、それらを含むクラスの外部のコードから簡単に見えないようにします(ただし、can 「あなたと同じように十分に決心していますcan Javaで保護されている場合、Javaの保護を回避します)。

同じ規則により、_プレフィックスは、技術的に禁止されていなくても離れることを意味します__foo_barのような別のクラスの変数をいじる必要はありません。

888
Kirk Strauser

Pythonのプライベート変数は多かれ少なかれハックです。インタプリタは意図的に変数の名前を変更します。

class A:
    def __init__(self):
        self.__var = 123
    def printVar(self):
        print self.__var

さて、クラス定義の外で__varにアクセスしようとすると失敗します。

 >>>x = A()
 >>>x.__var # this will return error: "A has no attribute __var"

 >>>x.printVar() # this gives back 123

しかし、これで簡単に解決できます。

 >>>x.__dict__ # this will show everything that is contained in object x
               # which in this case is something like {'_A__var' : 123}

 >>>x._A__var = 456 # you now know the masked name of private variables
 >>>x.printVar() # this gives back 456

OOPのメソッドが次のように呼び出されることをご存知でしょう。x.printVar() => A.printVar(x)A.printVar()x内のあるフィールドにアクセスできる場合は、このフィールドにもアクセスできますoutsideA.printVar()...結局、関数が作成されます。再利用性のために、内部の記述に特別な権限は与えられていません。

関係するコンパイラがある場合、ゲームは異なります(privacyはコンパイラレベルの概念です)。アクセス制御修飾子を持つクラス定義について知っているので、コンパイル時に規則に従わないとエラーになる可能性があります。

126
watashiSHUN

上記のコメントの多くで正しく言及されているように、Access Modifiersの主な目的を忘れないでください。コードのユーザーが何を変更すべきか、何を変更しないかを理解しやすくするため。あなたがプライベートフィールドを見たとき、あなたはそれを台無しにしません。そのため、Pythonでは_と__によって簡単に実現できます。

24
Ardavan

「Javaでは、パブリック/プライベート/保護変数について教えられました」

「なぜPythonではこれが必要ないのですか?」

同じ理由で、Javaでは required ではありません。

あなたは自由に使うことができます - あるいはprivateprotectedを使わないでください。

PythonとJavaのプログラマーとして、私はprivateprotectedが非常に非常に重要な設計概念であることを知りました。しかし実際問題として、何万行にも及ぶJavaとPythonでは、 実際に privateprotectedを使ったことは一度もありません。

何故なの?

これが私の質問です。

私のチームの他のプログラマーは?彼らはその源を持っています。保護されているとは、変更できるとはどういう意味ですか?

他のチームの他のプログラマー?彼らは同じ会社で働いています。彼らは - 電話で - 情報源を手に入れることができます。

クライアント?それは仕事用のプログラミング(一般的に)です。クライアントは(一般的に)コードを所有しています。

それで、だれが - 正確に - 私はそれを保護していますか?

18
S.Lott

アンダースコア規約には、プライベート変数のバリエーションがあります。

In [5]: class Test(object):
   ...:     def __private_method(self):
   ...:         return "Boo"
   ...:     def public_method(self):
   ...:         return self.__private_method()
   ...:     

In [6]: x = Test()

In [7]: x.public_method()
Out[7]: 'Boo'

In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()

AttributeError: 'Test' object has no attribute '__private_method'

微妙な違いがいくつかありますが、プログラミング・パターンのイデオロギー的な純粋さのためには、それで十分です。

概念をより厳密に実装する@privateデコレータの例はありますが、YMMVです。おそらく、メタを使用するクラス定義を書くこともできます。

13
Shayne

Pythonでは、クラス名の先頭に2つのアンダースコアで始まる識別子が自動的に追加される機能により、プライベート識別子のサポートが制限されています。これは、ほとんどプログラマにとっては透過的ですが、最終的には、この方法で指定された変数はすべてプライベート変数として使用できるようになります。

詳しくは ここ をご覧ください。

一般に、Pythonのオブジェクト指向の実装は、他の言語と比べて少し原始的です。しかし、私は実際にこれを楽しんでいます。これは非常に概念的に単純な実装であり、動的な言語のスタイルによく適しています。

9
Dan Olson

前述のように、変数またはメソッドの前にアンダースコアを付けることで、その変数またはメソッドがプライベートであることを示すことができます。これで十分ではないと思われる場合は、いつでもpropertyデコレータを使用できます。これが例です:

class Foo:

    def __init__(self, bar):
        self._bar = bar

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar

このように、barを参照する誰かまたは何かは、実際には変数自体ではなくbar関数の戻り値を参照しているため、アクセスできますが変更はできません。しかし、誰かが本当に望んでいるのであれば、彼らは単に_barを使用してそれに新しい値を割り当てることができます。繰り返し言われてきたように、誰かがあなたが隠したい変数やメソッドにアクセスするのを防ぐ確実な方法はありません。しかし、propertyを使用することは、変数が編集されないことをあなたが送ることができる最も明確なメッセージです。 propertyは、ここで説明されているように、より複雑なgetter/setter/deleterアクセス​​パスにも使用できます。 https://docs.python.org/3/library/functions.html#property

8
Isaac Saffold

私がこれまでプライベート変数を使用したのは、変数に読み書きするときに他のことをする必要があるときだけです。そのため、セッターやゲッターを使用する必要があります。

すでに述べたように、これも文化に当てはまります。私は他のクラスの変数を読み書きすることが自由にできるプロジェクトに取り組んできました。 1つの実装が非推奨になったとき、その関数を使用していたすべてのコードパスを識別するのにはるかに長い時間がかかりました。セッターとゲッターの使用を強制された場合、非推奨のメソッドが呼び出されたこととそれを呼び出すコードパスを識別するためのデバッグステートメントを簡単に書くことができます。

誰かがエクステンションを書くことができるプロジェクトでは、いくつかのリリースで廃止予定の廃止予定のメソッドについてユーザーに通知することが、アップグレード時のモジュール破損を最小限に抑えるために不可欠です。

私の答えはそうです。あなたとあなたの同僚が単純なコードセットを管理しているならば、クラス変数を保護することは必ずしも必要ではありません。あなたが拡張可能なシステムを書いているならば、それはコードを使用しているすべてのエクステンションによってキャッチされる必要があるコアへの変更がなされる時に必須になります。

8
BlueEagle

私的で保護された概念は非常に重要です。しかしpython - 開発のために利用可能な限られたリソースでプロトタイピングと迅速な開発のための単なるツールであるため、pythonではいくつかの保護レベルがそれほど厳格ではありません。あなたはクラスメンバの中で "__"を使うことができます、それは適切に動作します、しかし十分ではありません - そのようなフィールドへの各アクセスはこれらの文字を含みます。

また、python OOP概念は完璧ではなく、SmalltalkやRubyが純粋なOOP概念に非常に近いということに気付くでしょう。 C#やJavaでも近いです。

Pythonはとても良いツールです。しかし、それは単純化されたOOP言語です。文法的および概念的に単純化されています。 Pythonの存在の主な目的は、非常に速い方法で高い抽象化レベルで簡単に読みやすいコードを書く可能性を開発者にもたらすことです。

7
user711294

スレッドを「復活」させてくれて申し訳ありませんが、これが誰かに役立つことを願います。

Python 3では、Javaのように単にクラス属性を「カプセル化」したい場合は、次のように同じことを実行できます。

class Simple:
    def __init__(self, str):
        print("inside the simple constructor")
        self.__s = str

    def show(self):
        print(self.__s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

これをインスタンス化するには:

ss = Simple("lol")
ss.show()

print(ss.__s)はエラーをスローします。

実際には、Python 3はグローバル属性名を難読化します。 Javaのようにこれを "private"属性のように変える。属性の名前はまだグローバルですが、他の言語のプライベート属性のようにアクセスできない方法です。

しかし、それを恐れてはいけません。関係ありません。それは仕事もします。 ;)

4
Ferrarezi

PythonにはC++やJavaのようなプライベート変数はありません。必要に応じて、いつでもメンバー変数にアクセスできます。しかし、Pythonではプライベート変数は必要ありません。Pythonでは、クラスのメンバー変数を公開するのは悪くないからです。メンバー変数をカプセル化する必要がある場合は、後で "@property"を使用して既存のクライアントコードを壊すことなくこれを実行できます。

Pythonでは、単一のアンダースコア "_"は、メソッドや変数がクラスのパブリックAPIの一部とは見なされないこと、およびAPIのこの部分がバージョンによって異なる可能性があることを示すために使用されます。これらのメソッドや変数を使用できますが、このクラスの新しいバージョンを使用すると、コードが壊れる可能性があります。

二重下線「__」は「プライベート変数」を意味しません。 「クラスローカル」で、サブクラスで簡単に上書きできない変数を定義するために使用します。変数名を乱します。

例えば:

class A(object):
    def __init__(self):
        self.__foobar = None # will be automatically mangled to self._A__foobar

class B(A):
    def __init__(self):
        self.__foobar = 1 # will be automatically mangled to self._B__foobar

self .__ foobarの名前は、クラスAでは自動的にself._A__foobarに変換されます。クラスBではself._B__foobarに変換されます。したがって、すべてのサブクラスは、その親変数をオーバーライドすることなく、独自の変数__foobarを定義できます。しかし、二重下線で始まる変数にアクセスするのを妨げるものは何もありません。ただし、名前マングリングを使用すると、この変数やメソッドを誤って呼び出すことができなくなります。

私はRaymond HettingersがPycon 2013からの "Pythonsクラス開発ツールキット"(Youtubeで利用可能になるでしょう)を話すのを見ることを強くお勧めします。

2
Hatatister