質問

Python をますます使用するようになりましたが、変数が次のように表示されます。 __all__ 別の設定にします __init__.py ファイル。誰かこれが何をするのか説明してもらえますか?

役に立ちましたか?

解決

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

他のヒント

にリンクされていますが、ここでは明示的に言及されていませんが、まさにそのときです __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>.

正確に言うためにこれを追加しているだけです:

他のすべての回答は以下を参照しています モジュール. 。元の質問は明示的に言及されています __all____init__.py ファイルなので、これはPythonについてです パッケージ.

一般的に、 __all__ の場合にのみ機能します。 from xxx import * の亜種 import というステートメントが使用されます。これはモジュールだけでなくパッケージにも当てはまります。

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

要するに、 __all__ パッケージ レベルでは、モジュールの場合とほぼ同じことを行いますが、処理する点が異なります。 パッケージ内のモジュール (指定するのとは対照的に、 モジュール内の名前)。それで __all__ を使用するときに現在の名前空間にロードおよびインポートされるすべてのモジュールを指定します。 from package import *.

大きな違いは、 省略 の宣言 __all__ パッケージの中で __init__.py, 、ステートメント from package import * 何もインポートしません (ドキュメントで説明されている例外はあります。上記のリンクを参照してください)。

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

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 # makes directory a Python package
   |-module_1.py
   |-module_2.py

の中に __init__.py あなたが書く:

from module_1 import *
from module_2 import *

そしてで module_1 あなたが持っている:

__all__ = ['foo',]

そしてで module_2 あなたが持っている:

__all__ = ['Bar',]

これで、他の人がパッケージをインポートするときに使用できる完全な API が提示されました。次のようになります。

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

また、モジュールを作成するときに使用した他の名前がす​​べて付いて、ファイルが乱雑になることもありません。 package 名前空間。

__all____init__.py

さらに作業を行った結果、モジュールが大きすぎるため分割する必要があると判断したかもしれません。そこで、次のことを行います。

 package/
   |-__init__.py
   |-module_1/
   |  |-__init__.py
   |  |-foo_implementation.py
   |-module_2/
      |-__init__.py
      |-Bar_implementation.py

そしてそれぞれに __init__.py あなたは宣言します __all__, 、例えばmodule_1 内:

from foo_implementation import *
__all__ = ['foo']

そして module_2 の __init__.py:

from Bar_implementation import *
__all__ = ['Bar']

また、サブパッケージのモジュール レベルではなく、サブパッケージ レベルで管理できるものを 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

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

module1.py

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

module2.py

__all__ = ['a', 'b']

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

$ pydocモジュール1

Help on module module1:

名前
    module1

ファイル
    module1.py

データ
    ある = 'A'
    b = 'B'
    c = 'C'

$ pydocモジュール2

Help on module module2:

名前
    module2

ファイル
    module2.py

データ
    __全て__ = ['a', 'b']
    ある = 'A'
    b = 'B'

私は宣言する __all__ 私のすべてのモジュール、およびアンダースコアの内部詳細で、これらはライブ通訳セッションでこれまで使用したことのないものを使用するときに非常に役立ちます。

から (非公式) Python リファレンス Wiki:

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

__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 のファイル パッケージ __all__ パブリック モジュールまたはその他のオブジェクトの名前を含む文字列のリストです。これらの機能はワイルドカードインポートで利用できます。モジュールと同様に、 __all__ をカスタマイズします * パッケージからワイルドカードをインポートするとき。[@MartinStettner]

以下はその抜粋です Python MySQL コネクタ __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. 。これには、以前の import ステートメントによって明示的にロードされたパッケージのサブモジュールも含まれます。


ワイルドカードのインポート ...読者や多くの自動ツールを[混乱させる]ため、避けるべきです。

[PEP8, 、@ToolmakerSteve]

短い答え

__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 ドキュメントを表示できます ここ.

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

関連する抜粋は次のとおりです Python 言語リファレンス:

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

PEP8 も同様の文言を使用していますが、インポートされた名前がパブリック API の一部ではないことも明確にしています。 __all__ 欠席だ:

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

[...]

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

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

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

既存の回答に加えて、 __all__ リストである必要はありません。のドキュメントによると、 import 声明, 、定義されている場合、 __all__ でなければなりません 文字列のシーケンス これらは、モジュールによって定義またはインポートされた名前です。したがって、タプルを使用して、 保存 いくつかのメモリと CPU サイクル。モジュールが単一のパブリック名を定義する場合に備えて、カンマを忘れないでください。

__all__ = ('some_name',)

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top