web-dev-qa-db-ja.com

pythonでプライベートモジュール関数を定義する

http://www.faqs.org/docs/diveintopython/fileinfo_private.html によると:

ほとんどの言語と同様に、Pythonにはプライベート要素の概念があります。

  • モジュール外のから呼び出せないプライベート関数

ただし、2つのファイルを定義する場合:

#a.py
__num=1

そして:

#b.py
import a
print a.__num

b.pyを実行すると、1が例外なしで出力されます。 diveintopythonは間違っていますか、それとも何か誤解しましたか?そして、モジュールの機能をプライベートとして定義するdoする方法はありますか?

203
olamundo

Pythonでは、「プライバシー」は「同意する大人の」同意レベルに依存します-あなたはそれをforceすることはできません(実生活でできる以上;-)。単一の先行アンダースコアは、あなたが想定「外部から」アクセスすることではないことを意味します-two先行アンダースコア(後続アンダースコアなし)はメッセージをさらに強力に運びます...しかし、結局のところ、それはまだ社会的慣習とコンセンサスに依存しています:Pythonの内省はあなたが望みを尊重するためにhandcuff他のすべてのプログラマーができないほど強力です。

((ただし、それは密接に保持されている秘密ですが、C++にもほぼ同じです:ほとんどのコンパイラでは、#define private publicファイルを#includeingする前の単純な.h行が、あなたの「プライバシー」のハッシュを作成するのに必要です...! -))

272
Alex Martelli

class privatesmodule privates

A module private starts with one underscore
このような要素は、from <module_name> import *形式のインポートコマンドを使用するとコピーされません。ただし、import <moudule_name>構文を使用する場合はインポートされます( Ben Wilhelmの答えを参照
質問の例のa .__ numからアンダースコアを1つ削除するだけで、from a import *構文を使用してa.pyをインポートするモジュールに表示されなくなります。

A class private starts with two underscores (aka dunder i.e. d-ouble under-score)
そのような変数は、クラス名などを含めるために「マングル」という名前を持っています。
マングルされた名前を介して、クラスロジックの外部からアクセスできます。
名前のマングリングは、不正アクセスに対する軽度の防止デバイスとして機能しますが、その主な目的は、祖先クラスのクラスメンバーとの名前の衝突の可能性を防ぐことです。 Alex Martelliの同意成人に対する面白いが正確な参照を参照してください。これらの変数に関して使用される規則について説明しています。

>>> class Foo(object):
...    __bar = 99
...    def PrintBar(self):
...        print(self.__bar)
...
>>> myFoo = Foo()
>>> myFoo.__bar  #direct attempt no go
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__bar'
>>> myFoo.PrintBar()  # the class itself of course can access it
99
>>> dir(Foo)    # yet can see it
['PrintBar', '_Foo__bar', '__class__', '__delattr__', '__dict__', '__doc__', '__
format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__
', '__subclasshook__', '__weakref__']
>>> myFoo._Foo__bar  #and get to it by its mangled name !  (but I shouldn't!!!)
99
>>>
253
mjv

モジュールのプライバシーは純粋に慣習的なものではないため、またimportを使用するとモジュールのプライバシーが認識される場合とされない場合があるため、この質問は完全には答えられません。

モジュールでプライベート名を定義する場合、これらの名前willは、 'import module_name'構文を使用するスクリプトにインポートされます。したがって、この例のようにa.pyでプライベートモジュール_numを正しく定義したと仮定します。

#a.py
_num=1

..モジュール名シンボルを使用してb.pyでアクセスできます。

#b.py
import a
...
foo = a._num # 1

A.pyから非プライベートのみをインポートするには、from構文を使用する必要があります。

#b.py
from a import *
...
foo = _num # throws NameError: name '_num' is not defined

ただし、わかりやすくするために、モジュールから名前をインポートするときは、すべてを「*」でインポートするのではなく、明示的にする方が適切です。

#b.py
from a import name1 
from a import name2
...
73
Ben Wilhelm

Pythonでは、プライベートのclassが2つの下線プレフィックスを持つメンバーを許可します。この手法はモジュールレベルでは機能しないため、これはDive Into Pythonの間違いだと考えています。

プライベートクラス関数の例を次に示します。

class foo():
    def bar(self): pass
    def __bar(self): pass

f = foo()
f.bar()   # this call succeeds
f.__bar() # this call fails
29
Andrew Hare

内部関数を追加できます:

def public(self, args):
   def private(self.root, data):
       if (self.root != None):
          pass #do something with data

そのレベルのプライバシーが本当に必要な場合は、そのようなものが必要です。

7
Ilian Zapryanov

これは古くからの質問ですが、モジュールプライベート(アンダースコアが1つ)とクラスプライベート(アンダースコアが2つ)の両方のマングル変数は、標準のドキュメントでカバーされています。

Pythonチュートリアル " クラス " プライベート変数

1
user1338062

クロージャーまたは関数を埋め込むことは1つの方法です。これはJSでは一般的ですが、ブラウザ以外のプラットフォームやブラウザワーカーには必要ありません。

Pythonでは少し奇妙に思われますが、何かを本当に隠す必要がある場合は、それが道かもしれません。 python AP​​Iを使用して、C(または他の言語)で非表示にする必要があるものを保持することが、おそらく最良の方法です。失敗した場合、コードを関数内に配置し、それを呼び出して、エクスポートするアイテムを返します。

0
Martian Fame