web-dev-qa-db-ja.com

__main__。pyでモジュール独自のオブジェクトを使用する

__main__.py内からモジュールのデータにアクセスしようとしています。

構造は次のとおりです。

mymod/
    __init__.py
    __main__.py

さて、次のように__init__.pyで変数を公開すると:

__all__ = ['foo']
foo = {'bar': 'baz'}

__main__.pyからfooにアクセスするにはどうすればよいですか?

42
sharvey

パッケージがすでにsys.pathにあるか、mymodを含むディレクトリをsys.path__main__.pyに追加するか、-mスイッチを使用する必要があります。

パスにmymodを追加すると、次のようになります(__main__.py内)。

import sys
import os
path = os.path.dirname(sys.modules[__name__].__file__)
path = os.path.join(path, '..')
sys.path.insert(0, path)
from myprog import function_you_referenced_from_init_file

-mスイッチを使用すると、次のようになります。

python -m mymod

詳細については、 この回答 を参照してください。

23
pdemb

この種のことで私が最も遭遇する問題は、機能をテストするためのスクリプトとして__init__.pyファイルを実行したいことが多いということですが、パッケージをロードするときにこれらを実行しないでください。 python <package>/__init__.pypython -m <package>の間のさまざまな実行パスには便利な回避策があります。

  • $ python -m <module><package>/__main__.pyを実行します。 __init__.pyがロードされていません。
  • $ python <package>/__init__.pyは、通常のスクリプトのようにスクリプト__init__.pyを実行するだけです。


問題

__init__.pyif __name__ == '__main__': ...句を持たせたい場合ses__main__.pyのもの。 __main__.pyは、インタプリタのパスから常に__main__.pycをインポートするため、インポートできません。 (ただし…絶対パスインポートハックに頼りますが、これは他の多くの混乱を引き起こす可能性があります)。


ソリューション 解決策 :)

モジュールの__main__に2つのスクリプトファイルを使用します。

<package>/
         __init__.py
         __main__.py
         main.py

# __init__.py

# ...
# some code, including module methods and __all__ definitions

__all__ = ['foo', 'bar']
bar = {'key': 'value'}
def foo():
    return bar
# ...
if __name__ == '__main__':
    from main import main
    main.main()

# __main__.py

# some code...such as:
import sys
if (len(sys.argv) > 1 and sys.argv[1].lower() == 'option1'):
    from main import main()
    main('option1')
Elif (len(sys.argv) > 1 and sys.argv[1].lower() == 'option2'):
    from main import main()
    main('option2')
else:
    # do something else?
    print 'invalid option. please use "python -m <package> option1|option2"'

# main.py

def main(opt = None):
    if opt == 'option1':
        from __init__ import foo
        print foo()
    Elif opt == 'option2':
        from __init__ import bar
        print bar.keys()
    Elif opt is None:
        print 'called from __init__'

main.pyからのインポートは、__init__.pyに既にロードされているにもかかわらず、別のモジュールのローカルスコープにリロードしているため、__init__.pyから実行している場合はおそらく理想的ではありませんが、明示的なロードでは循環ロードを回避する必要があります。 __init__モジュール全体をmain.pyに再度ロードすると、__main__としてロードされないため、循環ロードに関する限り安全である必要があります。

4
Nisan.H

パッケージ__init__モジュールは、パッケージ自体のメンバーのように機能するため、オブジェクトはmymodから直接インポートされます。

from mymod import foo

または

from . import foo

簡潔にしたい場合は、 相対インポート について読んでください。いつものように、モジュールをmymod/__main__.pyとして呼び出さないようにする必要があります。これにより、Pythonがmymodをパッケージ。 distutils を調べてみてください。

2
Josh Lee

モジュールをpython -m mymodで実行すると、__main__.pyのコードは、モジュールをsys.pathに追加しなくても、モジュールの残りの部分からインポートできます。

1
glyphobet