Pythonのクラスには「プライベート」変数がありますか?


578

私はJavaの世界から来ており、Bruce EckelsのPython 3 Patterns、Recipes and Idiomsを読んでいます。

クラスについて読んでいる間、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 __name__ == "__main__":
    x = Simple("constructor argument")
    x.s = "test15" # this changes the value
    x.show()
    x.showMsg("A message")

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

Pythonでそれが必要とされないのはなぜですか?


17
クラス変数ではなくインスタンス変数を意味しましたよね?
PaulMcG 2009年

13
プロパティを確認する必要があります:docs.python.org/library/functions.html#property。ゲッターを使用するだけで、変数が保護されます。
ルービック

短くてはっきりとした答えがここにあります。これがお役に立てば幸いです。
Premkumar chalmeti

回答:


962

それは文化的です。Pythonでは、他のクラスのインスタンスやクラス変数には書き込みません。Javaでは、本当にしたい場合でも同じことを妨げるものは何もありません。結局のところ、いつでもクラス自体のソースを編集して同じ効果を得ることができます。Pythonは、そのような装いを落とし、プログラマーに責任を負わせるように働きかけます。実際には、これは非常にうまく機能します。

何らかの理由でプライベート変数をエミュレートする場合は、常にPEP 8の__プレフィックスを使用できます。Pythonはのような変数の名前を狂わせるあなたがたが(そう、彼らはクラス外部のコードに簡単に見えないだということ、それらを含んでいることができますしていると判定十分な場合は、同じように、それを回避することができますあなたはそれで作業する場合、Javaの保護を回避します)。__foo

同じ規則により、_プレフィックスは、技術的に禁止されていなくても近づかないことを意味します__fooまたはのような別のクラスの変数をいじってはいけません_bar


14
それは理にかなっている。ただし、Javaでクラス外のプライベート変数にアクセスする方法はないと思います(実際にクラスのソースを変更する場合を除く)。ある?
遍在

168
私はPythonの方法を好む傾向がありますが、Javaの方法はあなたが理解するほど無意味だとは思いません。プライベートなものを宣言すると、コードを読んでいる誰かにすぐに非常に役立つことがわかります。このフィールドは、このクラス内でのみ変更されます。
ネッド

67
@Omnipresent、リフレクションを使用できます。
rapadura

77
これを正直に言いますと、Pythonはパブリック属性もプライベート属性も実装していません。「セキュリティを装い、プログラマーに責任を負わせる」ためですが、コミュニティーはプライベート変数とメソッドを表すために「_」の使用を推奨していますか?たぶんpythonは明確にパブリックとプライベートNoを持っているべきですか?それらの主な目的は、クラスと対話するために使用する必要があるAPIを通知することです。これらは、これらのメソッドを使用し、使用しないように指示するドキュメントとして機能します。これらは「セキュリティの存在」ではなく、IDEがガイドとして使用できるAPIドキュメントです。
PedroD 2015年

19
これは良い答えであり、あなたの推論は確かに有効ですが、私は1つの側面に同意しません。アクセス修飾子の目的はセキュリティではありませんでした。むしろ、それらは、クラスのどの部分が内部と見なされ、そのクラスの外部ユーザーに公開されるかを明示的に(そして大体において)規定する手段です。規則(文化)はアクセス修飾子の有効な代替手段であり、どちらの方法にも長所と短所がありますが、言語レベルのアクセス修飾子は、通常の意味で「安全」であることが意図されているという目的を誤解しています。語。
devios1 2017年

159

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、このフィールドは外部に もアクセスできますA.printVar()...結局のところ、再利用性のために関数が作成され、内部のステートメントに特別な権限は与えられません。

コンパイラが関与している場合、ゲームは異なります(プライバシーはコンパイラレベルの概念です)。コンパイル時にルールが守られていない場合にエラーになる可能性があるため、アクセス制御修飾子を使用したクラス定義について知っています。


3
つまり、これはカプセル化ではありません
watashiSHUN

2
PHPは間抜けなプライベート変数と似たものがあるのでしょうか-プライベート変数はインタープリター型言語では実際には意味がないので、コンパイルされていない場合、x変数がプライベートであることを知っていれば、どのような最適化ができるでしょうか?
NoBugs

1
プライベート変数のパターンをランダム化するにはどうすればよいですか?
クリスロン2016

@crisron同じ質問
IanS 2016

5
@watashiSHUN「要するに、これはカプセル化ではない」=>はい、そうです。カプセル化はパブリックAPIのみを使用するため、クライアントコードは実装の変更から保護されます。命名規則は、APIと実装を区別するための完全に有効な方法です。要点は、APIが機能することです。
Bruno desthuilliers

30

上記のコメントの多くで正しく述べられているように、アクセス修飾子の主な目的を忘れないでください。コードのユーザーが何が変更されるべきか、何がそうでないべきかを理解できるようにするためです。あなたがプライベートフィールドを見たとき、あなたはそれをいじりません。そのため、Pythonで_および__を使用して簡単に実現できる構文上の砂糖です。


4
これは重要なポイントだと思います。コードをデバッグするとき(私は知っています、私はバグを導入するのが苦手です)、どのクラスがメンバー変数を変更できるかを知っていると、デバッグプロセスが簡単になります。少なくとも、変数が何らかのスコープによって保護されている場合。同様の概念は、C ++のconst関数です。私が知っているそのメンバ変数がそこには変化しなかったと私も悪い変数の設定の潜在的な原因として、その方法を見ないように。クラス拡張/機能の追加開発を行うことができますが、コードの可視性を制限することでデバッグが容易になります。
MrMas 2015年

18

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

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です。おそらく、メタを使用するクラス定義を書くこともできます


14
私はこれがパーティーにかなり遅れていることを理解していますが、問題をグーグルするときにこのリンクがグーグルに表示されます。これは全体の話ではありません。__xクラス内の変数Aは実際にはコンパイラによってに書き換えられるため_A__x、まだ完全にプライベートではなく、引き続きアクセスできます。
Zorf 2014年

1
もちろん、という名前の変数が表示された場合、その変数_A__xには触れません。伝染する可能性があります。私はそれから地獄を実行します。
Mateen Ulhaq 2017年

確かにそれは本当のプライベートではありません。しかし、C ++やJava(など)での強制的なプライベートの主な推論であるコンパイラの最適化は、Pythonには実際には存在しないため、慣例によるプライベートで十分です。Pythonの慣習では、一般に、監督なしで自分で行動することが信頼されています。(そして、それは初心者の罠ですが、ご存知のとおり、クラスの設計と消費については慎重に考えてください)
Shayne

14

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

「それがpythonで必要ないのはなぜですか?」

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

あなたは自由に使用できます-または使用privateしないでくださいprotected

PythonとJavaのプログラマーとして、私はそれを見つけたprivateprotected非常に、非常に重要な設計コンセプトです。しかし、実際問題として、JavaやPythonの行数万で、私は決してしました実際に使用されていませんprivateprotected

何故なの?

私の質問は「だれから守られているのか」です。

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

他のチームの他のプログラマー?彼らは同じ会社で働いています。彼らは-電話で-ソースを入手できます。

クライアント?これは、(一般的には)仕事のためのプログラミングです。クライアントは(通常)コードを所有します。

それで、私はそれを誰から保護しているのでしょうか?


119
-1:私はポーキュラスに同意します。それはアクセスを禁止したり何かを隠したりすることではなく、暗黙の APIドキュメントに関するものです。開発者だけでなく、コンパイラー/インタープリター/コードチェッカーも、どのメンバーを使用することが推奨されており、どのメンバーを変更すべきでないか(または少なくとも注意して)を簡単に確認できます。ほとんどの場合、クラスまたはモジュールのすべてのメンバーが公開されている場合、それは恐ろしい混乱になります。サービスとしてのプライベート/保護/パブリックメンバーの区別を検討してください:「ねえ、これらのメンバーは内部で使用されている間は重要であり、おそらくあなたには役に立たないでしょう。」
Oben Sonne、

7
@ S.Lott:APIドキュメントは優先度が高く、APIの使用目的を伝える唯一の方法であることに同意します。しかし、メンバーの名前と可視性(プライベート/パブリックの観点から)は、自分自身で十分に話すことがあります。また、暗黙のドキュメントのアイデアは、APIインスペクションのないエディターではうまく機能しないが、コード補完機能を備えたIDEで非常に役立つという点もおわかりでしょう。APIドキュメントを少し前に読んだことがあるとすると、クラスの使用方法を覚えておくと役立ちます。プライベートメンバーとパブリックメンバーを区別しなければ、物事はそれほどうまくいきません。
Oben Sonne

21
後期の議論が、すべてのものにPorculusとOBENは完全に適切大会「アンダースコアを前に付け」によって処理され、ここで要求している(とその大会のコンパイラの執行を引き起こす可能性があること害なし)
ncoghlan

38
@ S.Lott私はpythonの人ではないので、その観点からはコメントしません。しかし、Java開発者として、これは本当に恐ろしいアドバイスです。-1
dbyrne 2014

11
ワオ。あなたはポイントを完全に逃し、非常に悪いアドバイスを与え、あなたはこのポイントであなたに反対する人を侮辱しますが、それでもあなたはバッジとこの "答え"に対する1000以上の評判ポイントを得ます。
Eric Duminil 2017年

12

先に述べたように、変数またはメソッドの前にアンダースコアを付けることにより、変数またはメソッドがプライベートであることを示すことができます。これで十分ではない場合は、いつでも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


Djangoもこれを高く評価しています。
babygame0ver

10

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

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

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


うん。美しさは、Pythonのメタプログラミング機能は、必要に応じて実際にファンシーなものを実装できることを意味します(そして、@ private / @ protected / etcデコレータなどを実装するライブラリがあります。JSスタイルのプロトタイプクラスを実装したライブラリを見たことさえあります。ありがたい正気の理由ではありませんが、実際にはそれは必要ありません。「python / js / whatever is a lisp」ミームはほとんど真実ではないので嫌いですが、pythonは単純な構文と組み合わせた「メタプログラミングチョップ」を共有します'その言語
Shayne

8

私がプライベート変数を使用するのは、変数への書き込みまたは変数からの読み取り時に他のことを行う必要があるときだけです。そのため、セッターやゲッターを強制的に使用する必要があります。

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

誰もが拡張機能を記述できるプロジェクトにいる場合、いくつかのリリースで廃止される予定の非推奨メソッドについてユーザーに通知することは、アップグレード時にモジュールの破損を最小限に抑えるために不可欠です。

だから私の答えは あなたとあなたの同僚が単純なコードセットを維持している場合、クラス変数の保護は必ずしも必要ではありません。拡張可能なシステムを作成している場合、コードを使用してすべての拡張機能でキャッチする必要があるコアに変更が加えられると、それが不可欠になります。


8

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

Python3では、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)エラーがスローされます。

実際には、Python3はグローバル属性名を難読化します。これを、Javaのように「プライベート」属性のように変更します。属性の名前は依然としてグローバルですが、他の言語のプライベート属性のようにアクセスできません。

しかし、それを恐れないでください。それは問題ではありません。それも仕事をします。;)


2
これはPython 1.5.2 IIRC以降に存在し、マングルされた名前を介して属性にアクセスすることを妨げるものではありません。
Bruno desthuilliers

7

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

また、Python OOPの概念が完全ではなく、smaltalkまたはrubyが純粋なOOPの概念に非常に近いことに気づくでしょう。C#やJavaでも近いです。

Pythonは非常に優れたツールです。しかし、それは単純化されたOOP言語です。構文的にも概念的にも単純化されています。Pythonの存在の主な目的は、非常に高速な方法で、抽象化レベルの高い簡単に読み取り可能なコードを作成できるようにすることです。


PrivateとProtectedの重要な点は、静的にコンパイルされた言語では、コンパイラーがプライベートメソッドへの直接呼び出しを作成できるが、パブリックメソッドのルックアップテーブルに依存する必要があることです。Thiisは動的言語の問題ではありません。最後に、C ++のような言語は、継承とメソッド解決に影響を与えます。PythonとRubyはOOの実装が非常に似ているため、比較しても意味がありません。Smalltalkは実際にはパブリック/プライベートメッセージの概念を持ちません。カテゴリーとしてプライベートを自由に追加できますが、それは純粋に助言です。
Shayne

私の主張をさらに深めるために。衛生管理の観点から見て、カプセル化には重要ですが、必要ではありません。@ private(など)デコレータは何よりも助言ですが、プライベート/パブリックは、非静的言語、javaやcのようなコンパイル済み言語のように深いレベルで実装されていない
Shayne

4

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の「Pythonクラス開発ツールキット」(Youtubeで利用可能になるはずです)の講演を視聴することを強くお勧めします。これは、@ propertyおよび "__"-instance変数を使用する理由と方法の良い例です。


その話をチェックするつもりです。これは@property標準のPythonの一部ですか、それともIDEに固有ですか?
bballdave025

Python 2.6以降の標準の一部です。古いバージョンを使用する必要がある場合でも、propertyPython 2.2以降で利用可能な組み込み関数を使用する可能性があります
Hatatister

0

実際には、C#次の簡単なトリックを使用してゲッターとセッターをシミュレートできます。

class Screen(object):

    def getter_setter_y(self, y, get=True):
        if get is True:
            Screen.getter_setter_y.value = y
        else:
            return Screen.getter_setter_y.value

     def getter_setter_x(self, x, get=True):
         if get is True:
             Screen.getter_setter_x.value = x
         else:
             return Screen.getter_setter_x.value

次に、C#次のように使用します。

scr = Screen()
scr.getter_setter_x(100)
value =  scr.getter_setter_x(0, get=False)
print (value)

クラスまたはファイルに対してグローバルにせずに、getおよびsetメソッドを介して変数を共有する唯一の方法であるため、get / setの役割を果たす関数で静的ローカル変数を宣言するだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.