誰かがPythonで__all__を説明できますか?


983

私はますますPythonを使用しており、変数__all__が別の__init__.pyファイルに設定されるのを見続けています。誰かがこれが何をするか説明できますか?

回答:


566

これは、によって解釈される、そのモジュールのパブリックオブジェクトのリストですimport *。アンダースコアで始まるすべてを非表示にするデフォルトを上書きします。


146
アンダースコアで始まるオブジェクト、または存在する__all__場合__all__は言及されていないオブジェクトは、完全には非表示になりません。名前を知っていれば、通常どおり完全に表示およびアクセスできます。いずれにしても推奨されない「インポート*」の場合のみ、この区別が重要になります。
Brandon Rhodes、

28
@BrandonRhodes:それも厳密には当てはまりません:設計されていることがわかっているモジュールimport *(例:)のみをインポートすることをお勧めしますtk。これが当てはまる場合の良いヒント__all__は、モジュールのコードにアンダースコアで始まる名前または名前があることです。
空飛ぶ羊

12
パブリックおよび内部インターフェース-python.org/dev/peps/pep-0008/#id50、イントロスペクションをより適切にサポートするために、モジュールは__all__属性を使用して、パブリックAPIで名前を明示的に宣言する必要があります。__all__を空のリストに設定すると、モジュールにパブリックAPIがないことを示します。
デバッグ

tk今日(または2012年でさえ)がリリースされた場合、を使用することをお勧めしますfrom tk import *。私は慣習が意図的な設計ではなく慣性のために受け入れられていると思います。
chepner

BrandonRhodesが指摘するように、これは実際には正しくありません
duhaime

947

にリンクされていますが、ここでは明示的に言及されていませんが、がいつ__all__使用されるかが正確です。これは、モジュールfrom <module> import *で使用されたときに、モジュール内のどのシンボルがエクスポートされるかを定義する文字列のリストです。

たとえば、次のコードはfoo.py明示的にシンボルbarとをエクスポートしますbaz

__all__ = ['bar', 'baz']

waz = 5
bar = 10
def baz(): return 'baz'

これらのシンボルは、次のようにインポートできます。

from foo import *

print(bar)
print(baz)

# The following will trigger an exception, as "waz" is not exported by the module
print(waz)

場合は__all__上記のコメントアウトされたのデフォルトの動作として、このコードは、完了するまで実行されますimport *与えられた名前空間から、アンダースコアで始まらないすべてのシンボルをインポートすることです。

リファレンス:https : //docs.python.org/tutorial/modules.html#importing-from-a-package

注: 動作のみに__all__影響しfrom <module> import *ます。に記載されていないメンバーは__all__、モジュールの外部から引き続きアクセスでき、を使用してインポートできますfrom <module> import <member>


1
私たちはbazを次のように印刷すべきではありませんprint(baz())か?
ジョンコール

@JohnCole bazは関数オブジェクトであり、baz()は関数オブジェクトを実行します
Bhanu Tez

@BhanuTez正確に。だから、print(baz)のようなものを出力し<function baz at 0x7f32bc363c10>、一方、print(baz())プリントbaz
ジョン・コール

223

Pythonで__all__を説明しますか?

変数__all__が別の__init__.pyファイルに設定されているのを見続けます。

これは何をしますか?

何をし__all__ますか?

モジュールから意味的に「パブリック」な名前を宣言します。に名前がある場合__all__、ユーザーはそれを使用することが期待されており、変更されないことを期待できます。

また、プログラムによる影響もあります。

import *

__all__モジュール内、例えばmodule.py

__all__ = ['foo', 'Bar']

import *モジュールからの場合、にある名前のみ__all__がインポートされることを意味します:

from module import *               # imports foo and Bar

文書化ツール

ドキュメントとコードのオートコンプリートツールは、(実際には)を検査し__all__て、モジュールから利用可能として表示する名前を決定することもできます。

__init__.py ディレクトリをPythonパッケージにします

ドキュメントから:

__init__.pyファイルはPythonの御馳走パッケージを含むようにディレクトリを作成する必要があります。これは、文字列などの一般的な名前のディレクトリが、後でモジュール検索パスで発生する有効なモジュールを誤って非表示にしないようにするために行われます。

最も単純なケースで__init__.pyは、空のファイルにすることができますが、パッケージの初期化コードを実行したり、__all__変数を設定したりすることもできます。

だから、__init__.py宣言することができる__all__ためのパッケージ

APIの管理:

パッケージは通常、相互にインポートできるモジュールで構成されてい__init__.pyますが、ファイルで結合されている必要があります。そのファイルは、ディレクトリを実際のPythonパッケージにするものです。たとえば、パッケージに次のファイルがあるとします。

package
├── __init__.py
├── module_1.py
└── module_2.py

Pythonを使用してこれらのファイルを作成して、順を追ってみましょう。次のコードをPython 3シェルに貼り付けることができます。

from pathlib import Path

package = Path('package')
package.mkdir()

(package / '__init__.py').write_text("""
from .module_1 import *
from .module_2 import *
""")

package_module_1 = package / 'module_1.py'
package_module_1.write_text("""
__all__ = ['foo']
imp_detail1 = imp_detail2 = imp_detail3 = None
def foo(): pass
""")

package_module_2 = package / 'module_2.py'
package_module_2.write_text("""
__all__ = ['Bar']
imp_detail1 = imp_detail2 = imp_detail3 = None
class Bar: pass
""")

そして今、あなたは他の誰かがあなたのパッケージをインポートするときに次のように使用できる完全なapiを提示しました:

import package
package.foo()
package.Bar()

また、パッケージには、package名前空間を散らかすモジュールを作成するときに使用した他のすべての実装の詳細は含まれません。

__all____init__.py

さらに作業を行った後、モジュールが大きすぎ(数千行など)、分割する必要があると判断した可能性があります。したがって、次のことを行います。

package
├── __init__.py
├── module_1
│   ├── foo_implementation.py
│   └── __init__.py
└── module_2
    ├── Bar_implementation.py
    └── __init__.py

まず、モジュールと同じ名前のサブパッケージディレクトリを作成します。

subpackage_1 = package / 'module_1'
subpackage_1.mkdir()
subpackage_2 = package / 'module_2'
subpackage_2.mkdir()

実装を移動します。

package_module_1.rename(subpackage_1 / 'foo_implementation.py')
package_module_2.rename(subpackage_2 / 'Bar_implementation.py')

for each __init__.pyを宣言するサブパッケージのsを作成します__all__

(subpackage_1 / '__init__.py').write_text("""
from .foo_implementation import *
__all__ = ['foo']
""")
(subpackage_2 / '__init__.py').write_text("""
from .Bar_implementation import *
__all__ = ['Bar']
""")

そして今、あなたはまだパッケージレベルでプロビジョニングされたAPIを持っています:

>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>

また、サブパッケージのモジュールレベルではなく、サブパッケージレベルで管理できるものをAPIに簡単に追加できます。APIに新しい名前を追加する場合は__init__.py、たとえばmodule_2でを更新するだけです。

from .Bar_implementation import *
from .Baz_implementation import *
__all__ = ['Bar', 'Baz']

またBaz、トップレベルのAPIで公開する準備ができていない場合は、トップレベルで__init__.py次のようにすることができます。

from .module_1 import *       # also constrained by __all__'s
from .module_2 import *       # in the __init__.py's
__all__ = ['foo', 'Bar']     # further constraining the names advertised

ユーザーがの可用性を認識している場合はBaz、それを使用できます。

import package
package.Baz()

しかし、それについて知らない場合、他のツール(pydocなど)は通知しません。

後でBazプライムタイムの準備ができたら、それを変更できます。

from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']

接頭辞___all__

デフォルトでは、Pythonはで始まらないすべての名前をエクスポートします_。あなたは確かにこのメカニズムに頼ることができます。Pythonの標準ライブラリのいくつかのパッケージは、実際には、ないこれに依存しているが、中に、例えば、彼らは彼らの輸入を別名、そうしますctypes/__init__.py

import os as _os, sys as _sys

使用して_、それが再び名前を命名の冗長性を除去するので大会は、よりエレガントなことができます。ただし、インポートの冗長性が追加され(多数ある場合)、これを一貫して行うことを忘れがちです-そして、最後に必要なことは、実装の詳細のみを目的としたものを無期限にサポートする必要があることです。_関数に名前を付けるときにを前に付けるのを忘れたためです。

私は個人的__all__にモジュールの開発ライフサイクルの早い段階で記述し、私のコードを使用する可能性のある人が使用すべきものと使用すべきでないものを知っているようにします。

標準ライブラリのほとんどのパッケージでもを使用しています__all__

避けること__all__が理にかなっているとき

___all__場合の代わりに、接頭辞の規則に固執することは理にかなっています。

  • あなたはまだ初期の開発モードにあり、ユーザーがいないため、常にAPIを調整しています。
  • ユーザーはいるかもしれませんが、APIをカバーする単体テストがあり、APIに積極的に追加し、開発を微調整しています。

exportデコレータ

使用の欠点__all__は、エクスポートされる関数とクラスの名前を2回記述する必要があることであり、情報は定義とは別に保持されます。我々は可能性があり、この問題を解決するためにデコレータを使用しています。

私は、パッケージに関するDavid Beazleyの講演から、そのような輸出デコレータのアイデアを得ました。この実装は、CPythonの従来のインポーターでうまく機能するようです。特別なインポートフックまたはシステムがある場合は保証できませんが、採用した場合、バックアウトするのはかなり簡単です。名前を手動で追加するだけで、__all__

したがって、たとえば、ユーティリティライブラリでは、デコレータを定義します。

import sys

def export(fn):
    mod = sys.modules[fn.__module__]
    if hasattr(mod, '__all__'):
        mod.__all__.append(fn.__name__)
    else:
        mod.__all__ = [fn.__name__]
    return fn

次に、を定義する場所で__all__、次のようにします。

$ cat > main.py
from lib import export
__all__ = [] # optional - we create a list if __all__ is not there.

@export
def foo(): pass

@export
def bar():
    'bar'

def main():
    print('main')

if __name__ == '__main__':
    main()

そして、これはメインとして実行されても、別の関数によってインポートされても問題なく機能します。

$ cat > run.py
import main
main.main()

$ python run.py
main

また、APIプロビジョニングimport *も機能します。

$ cat > run.py
from main import *
foo()
bar()
main() # expected to error here, not exported

$ python run.py
Traceback (most recent call last):
  File "run.py", line 4, in <module>
    main() # expected to error here, not exported
NameError: name 'main' is not defined

1
相互参照:私は、デコレーターの書き方の質問に対するこのCWの回答であなたのデコレーターについて述べました@export
MvG 2017年

13
これは、単一の独力私は比較的新しいPythonの開発者がでたモジュール/パッケージをインポートするプロセスを理解する助けに関してで見た中で最も有用な答えとなっている__init__.pyとの使用__all__
ブレット・ラインハルト

これは私にとても役立ちます。私の問題は、インポートしたいすべてのサブモジュールが、手動で__all__正しいことを確認しなくても、除去したいシンボルに多くの残差がある生成ファイルであるということです。
Mike C

@MikeCでは、おそらくあなた__all__も生成する必要があります-しかし、不安定なAPIを使用していると言います...これは、いくつかの包括的な受け入れテストを行うためのものです。
アーロンホール

「彼らは...他のすべての名前を持つパッケージの名前空間を乱雑にしません」しかし、彼らは@AaronHall ます名前を持っているmodule_1module_2。明示的に含めるにはOKですdel module_1では__init__.py?これは価値があると思うのは間違っていますか?
Mike C

176

私は正確にこれを追加しています:

他のすべての回答はモジュールを参照しています。ファイルで明示的に言及さ__all__れている元の質問な__init__.pyので、これはpython パッケージに関するものです。

通常、ステートメント__all__from xxx import *バリアントimportが使用されている場合にのみ機能します。これは、モジュールだけでなくパッケージにも当てはまります。

モジュールの動作は他の回答で説明されています。ここでは、パッケージの正確な動作について詳しく説明します。

つまり、__all__パッケージレベルでは、モジュール内の名前 を指定するのとは対照的に、パッケージ内のモジュールを処理することを除いて、モジュールの場合とほぼ同じことを行います。したがって__all__、を使用するときに現在のネームスペースにロードおよびインポートされるすべてのモジュールを指定しますfrom package import *

大きな違いは、パッケージのでの宣言を省略した場合、ステートメントは何もインポートしないことです(例外はドキュメントで説明されていますが、上記のリンクを参照してください)。__all____init__.pyfrom package import *

一方、__all__モジュールで省略した場合、「スター付きインポート」はモジュールで定義されたすべての名前(アンダースコアで始まらない)をインポートします。


29
from package import *まだインポートすべてがで定義されていないだろう__init__.py何があっても、all。重要な違いは、__all__これがないと、パッケージのディレクトリで定義されているモジュールが自動的にインポートされないことです。
Nikratio 14

とき、すべてが私たちが使用している場合、[FOO、バー]とtest.pyファイルに含まれます。パッケージのインポート*から、その後、fooとbarは、fooとバー独自の名前空間test.pyのかでローカル名前空間にインポートしたのですか?
可変

87

また、pydocが表示する内容も変更されます。

module1.py

a = "A"
b = "B"
c = "C"

module2.py

__all__ = ['a', 'b']

a = "A"
b = "B"
c = "C"

$ pydoc module1

モジュールmodule1のヘルプ:

名前
    module1

ファイル
    module1.py

データ
    a = 'A'
     b = 'B'
     c = 'C'

$ pydoc module2

モジュールmodule2のヘルプ:

名前
    module2

ファイル
    module2.py

DATA 
    __all__ = ['a'、 'b']
     a = 'A'
     b = 'B'

__all__はすべてのモジュールと下線の内部詳細を宣言します。これらは、ライブインタープリターセッションでこれまで使用したことがないものを使用するときに本当に役立ちます。


54

__all__カスタマイズ*from <module> import *

__all__カスタマイズ*from <package> import *


モジュールがあり.py、インポートされることを意図したファイル。

パッケージが持つディレクトリで__init__.pyファイル。パッケージには通常モジュールが含まれています。


モジュール

""" cheese.py - an example module """

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99

__all__モジュールの「公開」機能を人間に知らせます[ @AaronHall ] また、pydocはそれらを認識します。[ @ロングポーク ]

モジュールのインポートから*

どのようにしてローカル名前空間に取り込まれるかswissを確認しcheddarてくださいgouda

>>> from cheese import *
>>> swiss, cheddar
(4.99, 3.99)
>>> gouda
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'gouda' is not defined

がなければ__all__、任意の記号(アンダースコアで始まらない)を使用できます。


なしのインポート*は影響を受けません__all__


インポートモジュール

>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)

モジュールのインポートから

>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)

モジュールローカル名としてインポート

>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)

パッケージ

パッケージ__init__.pyファイルには、パブリックモジュールまたは他のオブジェクトの名前を含む文字列のリストがあります。これらの機能は、ワイルドカードインポートで使用できます。モジュールと同様に、パッケージからワイルドカードをインポートするときにをカスタマイズします。[ @MartinStettner ] __all____all__*

これは、Python MySQL Connector からの抜粋です__init__.py

__all__ = [
    'MySQLConnection', 'Connect', 'custom_error_exception',

    # Some useful constants
    'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
    'HAVE_CEXT',

    # Error handling
    'Error', 'Warning',

    ...etc...

    ]

デフォルトのケースである、パッケージアスタリスクがない__all__場合は、明白な動作が高くつくため、複雑です。つまり、ファイルシステムを使用してパッケージ内のすべてのモジュールを検索します。代わりに、私のドキュメントの読み取りでは、で定義されたオブジェクトのみ__init__.pyがインポートされます。

__all__が定義されていない場合、ステートメントfrom sound.effects import *はパッケージからすべてのサブモジュールを現在の名前空間にインポートしませsound.effects。パッケージsound.effectsがインポートされたことを確認するだけで(おそらくで初期化コードが実行されます__init__.py)、パッケージで定義されている名前をインポートします。これには、によって定義された名前(および明示的にロードされたサブモジュール)が含まれ__init__.pyます。また、前のインポート文によって明示的にロードされたパッケージのサブモジュールも含まれています。


ワイルドカードインポート...は、読者や多くの自動化ツールを[混乱]させるため、避けてください。

[ PEP 8、@ ToolmakerSteve]


2
私は本当にこの答えのように、私はのためのデフォルトの動作何の情報が欠落していfrom <package> import *なくて__all____init__.pyされているモジュールのいずれかをインポートしません
radzak

@Jatimirに感謝します。実験を行わずにできる限りのことを明確にしました。私はほとんどこのケース(パッケージのすべてなしのアスタリスク)がモジュールの場合__init__.pyと同じように動作することを言いたかったです。しかし、それが正確であるかどうか、特にアンダースコアが前に付いているオブジェクトが除外されている場合はわかりません。また、モジュールとパッケージのセクションをより明確に分離しました。あなたの考え?
Bob Stein

49

(アン非公式)Pythonリファレンスウィキ

モジュールによって定義されたパブリック名は、モジュールの名前空間でと名付けられた変数をチェックすることによって決定され__all__ます。定義されている場合、そのモジュールによって定義またはインポートされた名前である文字列のシーケンスである必要があります。に記載されている名前__all__はすべてパブリックと見なされ、存在する必要があります。__all__が定義されていない場合、パブリック名のセットには、アンダースコア文字( "_")で始まっていない、モジュールの名前空間にあるすべての名前が含まれます。__all__パブリックAPI全体を含める必要があります。これは、APIの一部ではないアイテム(インポートされ、モジュール内で使用されたライブラリモジュールなど)を誤ってエクスポートしないようにすることを目的としています。


リストされたリンクは無効です。しかし、vdocuments.net / およびここにdobatmen.tips/documents/reference-567bab8d6118a.html
JayRizzo

8

__all__PythonモジュールのパブリックAPIを文書化するために使用されます。オプションですが、__all__使用する必要があります。

Python言語リファレンスからの関連する抜粋を次に示します

モジュールによって定義されたパブリック名は、モジュールの名前空間でと名付けられた変数をチェックすることによって決定され__all__ます。定義されている場合、そのモジュールによって定義またはインポートされた名前である文字列のシーケンスである必要があります。に記載されている名前__all__はすべてパブリックと見なされ、存在する必要があります。__all__が定義されていない場合、パブリック名のセットには、アンダースコア文字( '_')で始まっていない、モジュールの名前空間にあるすべての名前が含まれます。__all__パブリックAPI全体を含める必要があります。これは、APIの一部ではないアイテム(インポートされ、モジュール内で使用されたライブラリモジュールなど)を誤ってエクスポートしないようにすることを目的としています。

PEP 8も同様の表現を使用していますが、__all__がない場合、インポートされた名前がパブリックAPIの一部ではないことも明確になっています。

イントロスペクションをより適切にサポートするために、モジュールは__all__属性を使用してパブリックAPIで名前を明示的に宣言する必要があります。__all__空のリストに設定すると、モジュールにパブリックAPIがないことを示します。

[...]

インポートされた名前は常に実装の詳細と見なされます。他のモジュールは、それらが含まれるモジュールのAPIのように明示的に文書化された部分、os.pathまたは__init__サブモジュールから機能を公開するパッケージのモジュールでない限り、そのようなインポートされた名前への間接アクセスに依存してはなりません。

さらに、他の回答で指摘され__all__ているように、パッケージのワイルドカードインポートを有効にするために使用されます

importステートメントは次の規則を使用します。パッケージの__init__.pyコードがという名前のリストを定義する場合__all__、それは、が検出されたときにインポートする必要があるモジュール名のリストであると解釈されますfrom package import *


8

簡潔な答え

__all__from <module> import *ステートメントに影響します。

長い答え

この例を考えてみましょう:

foo
├── bar.py
└── __init__.py

foo/__init__.py

  • (暗黙)を定義しない場合__all__、でfrom foo import *定義されfoo/__init__.pyた名前のみがインポートされます。

  • (明示)を定義すると__all__ = []from foo import *何もインポートされません。

  • (明示)を定義すると__all__ = [ <name1>, ... ]from foo import *それらの名前のみがインポートされます。

暗黙的なケースでは、pythonはで始まる名前をインポートしないことに注意してください_。ただし、を使用してそのような名前を強制的にインポートできます__all__

こちらのPythonドキュメントをご覧ください


5

__all__動作に影響しますfrom foo import *

モジュール本体の内部(関数またはクラスの本体ではない)のコードでは*fromステートメントでアスタリスク()を使用できます。

from foo import *

*モジュールのすべての属性という要求foo(アンダースコアで始まるものを除く)をインポートモジュール内のグローバル変数としてバインドされます。ときにfoo属性を持つ__all__、属性の値は、このタイプによってバインドされている名前のリストですfromステートメント。

場合foo、パッケージとその__init__.py定義という名前のリスト__all__、ときにインポートする必要があるサブモジュール名のリストであると解釈されてfrom foo import *検出されました。が定義されて__all__いない場合、ステートメントfrom foo import *はパッケージで定義されている名前をインポートします。これには、によって定義された名前(および明示的にロードされたサブモジュール)が含まれ__init__.pyます。

__all__リストである必要はありません。上のドキュメントごとにimport声明、定義されている場合は、__all__でなければならない一連の文字列モジュールで定義されたまたはインポートの名前です。したがって、タプルを使用してメモリとCPUサイクルを節約することもできます。モジュールが単一のパブリック名を定義する場合に備えて、コンマを忘れないでください。

__all__ = ('some_name',)

「インポート*」が悪いのはなぜですか?も参照してください


1

これはPEP8でここに定義されています

グローバル変数名

(これらの変数が1つのモジュール内でのみ使用されることを目的としています。)規則は関数の規則とほぼ同じです。

via from M import *を使用するように設計されたモジュールは、__all__グローバルのエクスポートを防止するメカニズムを使用するか、そのようなグローバルの前に下線を付けるという従来の規則を使用する必要があります(これらのグローバルが「モジュール非公開」であることを示すために実行する場合があります)。

PEP8は、メインのPythonディストリビューションの標準ライブラリを構成するPythonコードのコーディング規約を提供します。これに従うほど、元の意図に近づきます。

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