Python のプライベートメンバー
-
20-09-2019 - |
質問
Python でメソッドとデータ メンバーをプライベートにするにはどうすればよいですか?それとも Python はプライベートメンバーをサポートしていないのでしょうか?
解決
「プライベート」インスタンス変数もの 内側以外からアクセスすることはできません オブジェクトは、Pythonで存在していません。 しかし、ある規則があります 名前:ほとんどのPythonコードが続きます 下線接頭辞(例えば _spam()APIの非パブリック一部として扱われるべきであることか 機能、方法、またはデータであります メンバー)。これは、考慮すべき 実装の詳細と対象 予告なしに変更ます。
の有効なユースケースがあるため クラスのプライベートメンバー(すなわち避けるために、 名前と名前の衝突に名前を付けます )サブクラスによって定義され、そこにあります このようなメカニズムのための限定的なサポート、 名前マングリングと呼ばれます。任意の識別子 フォーム__spam(少なくとも二つの ほとんど1で先頭のアンダースコア、 末尾のアンダースコア)がテキストであります
_classname__spam
、と置き換え クラス名は、現在のクラス名です。 先頭の下線(S)でストリッピングしました。 このマングリングは関係なく行われます の構文位置へ 限り、それが発生するなどの識別子、 クラスの定義内でます。
だから、例の、
class Test:
def __private_symbol(self):
pass
def normal_symbol(self):
pass
print dir(Test)
が出力されます:
['_Test__private_symbol',
'__doc__',
'__module__',
'normal_symbol']
__private_symbol
は、プライベートメソッド考慮しなければならないが、それはまだ_Test__private_symbol
を介してアクセス可能になります。
他のヒント
他の回答には、技術的な詳細を提供しています。私は1つの手と(私はあなたがあなたの質問をもとに精通していると推定)C ++ / Javaのような言語でPythonとの哲学の違いを強調したいと思います。
(そのことについてとPerl)Pythonで一般的な態度は、属性の「プライバシー」は、プログラマではなく、コンパイラ/インタプリタによって、有刺鉄線のフェンスへの要求であるということです。アイデアはhref="http://mail.python.org/pipermail/tutor/2003-October/025932.html" rel="noreferrer">このメールとしばしば呼ばれている
あなたがを場合は、 一方、
ここにはない private
Python の他のアクセス保護メカニズム。に文書化された規約があります。 Python スタイルガイド クラスのユーザーに特定の属性にアクセスしてはならないことを示すために使用されます。
_single_leading_underscore:弱い「内部使用」インジケーター。例えば。
from M import *
名前がアンダースコアで始まるオブジェクトはインポートしません。single_trailing_underscore_:Python キーワードとの競合を避けるために慣例的に使用されます。
Tkinter.Toplevel(master, class_='ClassName')
__double_leading_underscore:クラス属性に名前を付けるときに、名前マングリングを呼び出します (クラス FooBar 内では、__boo は _FooBar__boo になります。以下を参照してください)。
もしの Python関数の名前、 クラスメソッド、または属性で始まります (しかし、で終わっていない)2 アンダースコア、それはプライベートです; のすべてのもの 他にはpublicです。 Pythonは概念がありません 保護されたクラスメソッドの(アクセス可能 唯一、自分のクラスと子孫で クラス)。クラスメソッドのいずれかです (プライベートのみ、自分の中にアクセス可能 クラス)またはパブリック(からアクセス どこでも)。
Pythonが直接、プライバシーをサポートしていません。プログラマは、あなたが少しトリックとプライベートのような何かを達成することができますのpythonで外とにかくからの属性を変更しても安全であるとき知っておく必要があります。 今の人はそれにプライベート何かを入れたりすることはできません見てみましょう。
class Person(object): def __priva(self): print "I am Private" def publ(self): print " I am public" def callpriva(self): self.__priva()
今、私たちが実行されたときます:
>>> p = Person() >>> p.publ() I am public >>> p.__priva() Traceback (most recent call last): File "", line 1, in p.__priva() AttributeError: 'Person' object has no attribute '__priva' #Explanation : You can see here we are not able to fetch that private method directly. >>> p.callpriva() I am Private #Explanation : Here we can access private method inside class
すると誰かが???
その変数にアクセスする方法
あなたが好き行うことができます:
>>>p._Person__priva I am Private
うわー、実際のpythonを二重下線で始まる変数は先頭にアンダースコアとクラス名を追加することにより、「翻訳」されてきている場合:
注:あなたは、この名前は変更したくない場合がありますが、まだ他のオブジェクトが離れて滞在するための信号を送信したい、あなたは最初のアンダースコアで単一最初のアンダースコアの名前を使用することができません(モジュールのインポート*から)主演の輸入で輸入
例:
#test.py def hello(): print "hello" def _hello(): print "Hello private" #----------------------
#test2.py from test import * print hello() print _hello()
出力 - >
hello Traceback (most recent call last): File "", line 1, in NameError: name '_hello' is not defined
今、私たちは手動で_hello呼ぶ場合ます。
#test2.py from test import _hello , hello print hello() print _hello()
出力 - >
hello hello private
最後に:単一ものの、Pythonは本当に、同等のプライバシーをサポートしていません。 ダブル最初のアンダースコアはあなたのプライバシーの二つのレベルを与えるある程度まで行う。
これは動作します。
import sys, functools
def private(member):
@functools.wraps(member)
def wrapper(*function_args):
myself = member.__name__
caller = sys._getframe(1).f_code.co_name
if (not caller in dir(function_args[0]) and not caller is myself):
raise Exception("%s called by %s is private"%(myself,caller))
return member(*function_args)
return wrapper
class test:
def public_method(self):
print('public method called')
@private
def private_method(self):
print('private method called')
t = test()
t.public_method()
t.private_method()
これはちょっと、L-O-N-Gの答えですが、私はそれがここでの本当の問題の根本になると思います - 可視性の範囲。私はこれを通じて強打しながら、そこにハングアップする!
単にモジュールをインポートすることは、必ずしもそのクラスやメソッドのすべてにアプリケーション開発者のアクセス権を与える必要はありません。私は実際にモジュールのソースコードを見ることができない場合はどのように私が利用可能です知っているのだろうか?いくつかの1つ(またはいくつかのことは)そうでない場合は、全体の事は私には役に立たない、私は何ができるかを教え、私が使用を許可されていますこれらの機能を使用する方法について説明しています。
NOT実際のソースコード -インポートモジュールを介して、基本的なクラスやメソッドに基づくもの現像より高いレベルの抽象化は、仕様書で提示されます。
モジュール仕様は、クライアント開発者に可視であることを意図し、すべての機能について説明します。大規模なプロジェクトやソフトウェアのプロジェクトチームを扱う場合、モジュールの実際の実装は、常にそれを使用して、それらから隠れたままにしてください - それは外の世界とのインタフェースを持つブラックボックスです。 OODの純粋主義者のために、私は専門的用語は、「デカップリング」と「一貫性」であると信じています。モジュールのユーザーは、実装の詳細を負担することなく、インタフェースのメソッドを知っている必要があります。
モジュールは、第1のコードを変更する前に、いくつかの組織で審査/承認が必要になることがあり、その基本的なスペックの文書を、変更せずに変更すべきではありません。
(現在は引退)趣味のプログラマーとして、私は実際にモジュールの上部にある巨大なコメントブロックとして書き出さスペックドキュメントで新しいモジュールを開始し、これは、ユーザが実際にスペックライブラリに見ている一部となります。それは私だけなので、私は、ライブラリを設定するにはまだきたが、行うのに十分簡単だろう。
それから私は、さまざまなクラスやメソッドを書くことではなく、機能の体ずにコーディングを開始 - 「印刷()」のように、単にヌルprint文 - モジュールは構文エラーなしでコンパイルすることを可能にするだけで十分。このステップが完了すると、私は完成し、ヌル・モジュールをコンパイルする - これが私の仕様です。私はプロジェクトチームで作業していた場合、私は体を肉付けを進める前にレビュー&解説のために、この仕様/インタフェースを提供してしまいます。
私は一度に各一方法の本体を肉付けし、それに応じてコンパイル、構文エラーをオンザフライで直ちに固定されて確実。また、これはあなたがそれをコードとして各メソッドをテストするために下部に、一時的な「メイン」実行部を書き始めるのに良い時期です。コーディング/テストが完了したら、あなたはそれが再び更新が必要になるはず必要になるまで、テストコードのすべてがコメントアウトされています。
実世界の開発チームでは、スペックのコメントブロックは、文書管理ライブラリに表示されますが、それはまた別の話です。ポイントは次のとおりです。あなたは、モジュールのクライアントとして、これだけスペックとNOTソースコードを参照してください。
PS:長い時間の開始前に、私は防衛航空宇宙コミュニティで働いていたし、私たちはかなりクールなものをしましたが、独自のアルゴリズムや敏感なシステム制御ロジックのようなものがしっかりとアーチ型や超大型のセキュアなソフトウェアライブラリで暗号化されました。私たちは、モジュール/パッケージのインタフェースではなく、ブラックボックスの実装機関へのアクセスを持っていました。それはすべて一緒に同期されました - すべてのシステムレベルの設計、ソフトウェアの仕様、ソースコードとテストレコードを処理し、文書管理ツールがありました。政府は厳格な要件のソフトウェア品質保証基準を持っていました。誰もが「エイダ」と呼ばれる言語を覚えていますか?それは私が何歳だ!
私は、Python 2.7と3.5を使用しています。私はこのコードを書いてます:
class MyOBject(object):
def __init__(self):
self.__private_field = 10
my_object = MyOBject()
print(my_object.__private_field)
は、それを実行して得ます:
はAttributeError: 'MyObjectに' オブジェクトが属性を持っていない '__private_field'
を参照してください。 https://www.tutorialsteacher.com/python/民間と保護 - アクセス修飾子・イン・パイソンの
あなたはPythonでプライベートメソッドまたはデータメンバを作りたい場合は、
__ __setattr使用class Number:
def __init__(self,value):
self.my_private = value
def __setattr__(self, my_private, value):
# the default behavior
# self.__dict__[my_private] = value
raise Exception("can't access private member-my_private")
def main():
n = Number(2)
print(n.my_private)
if __name__ == '__main__':
main()