web-dev-qa-db-ja.com

Pythonの "Private"(実装)クラス

私は2つの部分で構成される小さなPythonモジュールをコーディングしています:

  • パブリックインターフェイスを定義するいくつかの関数、
  • 上記の関数で使用される実装クラスですが、モジュールの外部では意味がありません。

最初に、この実装クラスを使用して関数内で定義することにより、この実装クラスを「隠す」ことにしましたが、これは読みやすさを妨げ、複数の関数が同じクラスを再利用する場合は使用できません。

では、コメントとdocstringに加えて、クラスを「プライベート」または「内部」としてマークするメカニズムはありますか?私はアンダースコアのメカニズムを知っていますが、理解しているように、それは変数、関数、メソッド名にのみ適用されます。

92
oparisy

単一の下線プレフィックスを使用します。

class _Internal:
    ...

これは公式のPython 'internal'シンボルの規約です。 "from module import *"はアンダースコアで始まるオブジェクトをインポートしません。

編集: 単一アンダースコア規則 への参照

148
Ferdinand Beyer

要するに:

  1. プライバシーを強制することはできません。 Pythonにはプライベートクラス/メソッド/関数はありません。少なくとも、Javaなどの他の言語のような厳格なプライバシーはありません。

  2. プライバシーを示す/示唆することしかできません。これは規則に従います。クラス/関数/メソッドをプライベートとしてマークするためのpython規則は、_(アンダースコア)で始まります。たとえば、def _myfunc()またはclass _MyClass:。メソッドの前に2つのアンダースコアを付けることにより、疑似プライバシーを作成することもできます(例:__foo)。メソッドに直接アクセスすることはできませんが、クラス名を使用して特別なプレフィックスを使用して呼び出すことができます(例:_classname__foo)。したがって、できる最善の方法は、プライバシーを強制するのではなく、プライバシーを示す/提案することです。

この点で、PythonはPerlに似ています。 Perlの本からプライバシーに関する有名な言葉を言い換えると、哲学は、ショットガンで守られているからではなく、招待されていないので、居間から離れるべきだというものです。

詳細については:

59
Karl Fast

定義__all__、エクスポートする名前のリスト( ドキュメントを参照 )。

__all__ = ['public_class'] # don't add here the 'implementation_class'
35
UncleZeiv

私が時々使うパターンはこれです:

クラスを定義します。

class x(object):
    def doThis(self):
        ...
    def doThat(self):
        ...

クラスのインスタンスを作成し、クラス名を上書きします。

x = x()

機能を公開するシンボルを定義します。

doThis = x.doThis
doThat = x.doThat

インスタンス自体を削除します。

del x

これで、パブリック関数のみを公開するモジュールができました。

10
theller

規則は、内部クラス、関数、および変数の前に「_」を追加します。

8

設計規約の問題に対処するために、そしてクリストファーが言ったように、Pythonには「プライベート」のようなものは本当にありません。これは、C/C++のバックグラウンドから来た人にとってはひねくれたように聞こえるかもしれません(しばらく前のように)。

前に下線が付いているものを見ると、直接使用しないのに十分なヒントになるはずです。 help(MyClass)の出力が乱れている場合(クラスの使用方法を検索するときに誰もが見ているもの)、下線付きの属性/クラスはそこに含まれていないので、最終的には「パブリック」インターフェースの説明。

さらに、すべてを公開することには、たとえば、外部からほとんど何でもユニットテストできる(C/C++プライベートコンストラクトでは実行できない)など、独自の素晴らしい特典があります。

4
Dimitri Tcaciuc

「プライベート」識別子の名前の前に2つのアンダースコアを使用します。モジュール内のクラスの場合、単一の先頭アンダースコアを使用し、「from module import *」を使用してインポートされません。

class _MyInternalClass:
    def __my_private_method:
        pass

(Pythonには真の「プライベート」というものはありません。たとえば、Pythonは、自動的にクラスメンバーの名前を二重アンダースコアで__clssname_mymemberにマングルします。とにかく「プライベート」エンティティを使用できるマングルされた名前を知っている こちらを参照 そしてもちろん、必要に応じて「内部」クラスを手動でインポートすることもできます)。

2
chroder