私は次のようなディレクトリ構造を持っています:
Package/
setup.py
src/
__init__.py
__main__.py
code.py
さまざまな方法でコードを実行できるようにしたいと考えています。
pip install Package
、python
、from Package import *
python -m Package
は__main__.py
の処理を行う必要があります
python __main__.py
も__main__.py
の機能を実行する必要がありますが、今回は、pip installing
ではなくソースをダウンロードしたと仮定します。
これで最初の2つが機能するようになりましたが、設定が面倒です:
setup.py:
setup(
name='Package',
packages=['Package'],
package_dir={'Package': 'src'},
...
entry_points={ 'console_scripts': ['Package = src.__main__:main' ] }
__ init__.py:
from Package.code import .......
__ main__.py:
from . import .......
私にとってより理にかなっているのは、両方の場合に書くことです
from code import ........
しかし、それはインポートエラーを与えます。
私が持っている方法は本当に唯一の方法ですか?
そして最も重要なことは、3番目のユースケースをどのようにサポートするかということです。今、python __main__.py
がスローします
File "__main__.py", line 10, in <module>
from . import code
ImportError: cannot import name 'class defined in code.py'
読みました
必要なものはほぼすべて揃っています(もう少し)。私は次のセットアップで行きます:
code.py:
foo = 1
__ init__.py:
from .code import foo
パッケージ全体をインポートするときに__init__.py
が使用されるため、ここで相対インポートを実行します。 Python 3(および.
を実行した場合はPython 2)に必要であるため、from __future__ import absolute_import
-- syntaxを使用してインポートを明示的に相対としてマークすることに注意してください。
__ main__.py:
from Package import foo
print('foo = ', foo)
これはパッケージのメインスクリプトであるため、絶対import
ステートメントを使用します。そうすることで、パッケージがインストールされている(または少なくともパスに置かれている)と仮定します。それがパッケージの扱い方です!これは3番目のユースケースと競合すると思うかもしれませんが、実際にはパッケージを扱うときにpip install
に理由notはありません。そして、それは本当に大したことではありません(特に virtualenv
を使用する場合)!
ソースファイルをいじり、__main__.py
ファイルを実行して簡単に変更を確認する場合は、-e
(「編集可能」)スイッチを使用してパッケージをインストールするだけです。pip install -e .
(ディレクトリPackage
)。ただし、現在のディレクトリ構造では、-e
スイッチがEgg-link
をsetup.py
ファイルを含むディレクトリに配置するため、これは機能しません。このディレクトリにはPackage
という名前のパッケージは含まれていませんが、代わりにsrc
という名前があります(私は それに関する質問 を持っています)。
代わりに、パッケージ自体(例ではPackage
)に基づいてパッケージのソースのルートディレクトリに名前を付ける規則に従っている場合、-e
を使用したインストールは問題ありません:Pythonは、対応するディレクトリで必要なパッケージPackage
を検索します:
$ tree Package/
Package/
├── setup.py
└── Package <-- Renamed "src" to "Package" because that's the package's name.
├── code.py
├── __init__.py
└── __main__.py
これにより、package_dir={'Package': 'src'}
のsetup.py
の追加の定義を省略できます。
setup.py
に関する注意:指定した3つのユースケースでは、エントリポイントを定義する必要はありません。つまり、entry_points={ 'console_scripts': ['Package = src.__main__:main' ] }
行をスキップできます。 __main__.py
モジュールを出荷することにより、python -m Package
はこのモジュールのコードを容易に実行します。追加のif節を追加することもできます。
def main():
print('foo = ', foo)
if __== '__main__':
main()
一方、エントリポイントを使用すると、CLIから__main__.main
のコードを直接実行できます。 $ Package
を実行すると、対応するコードが実行されます。
一番下の行は、パッケージを扱うときに常にpip install
を使用するということです。そして、特にsetup.py
ファイルをすでに作成している場合はどうでしょうか?パッケージへの変更を「リアルタイム」で適用する場合は、-e
スイッチを使用してインストールできます(これには、src
フォルダーの名前変更が必要になる場合があります。上記を参照)。したがって、3番目の使用例は、「ソースとpip install (-e) Package
(virtualenv内)をダウンロードし、その後python __main__.py
を実行できます」と読みます。
__main__.py
なしでpip install
を実行するPipを介してパッケージをインストールしたくないが、__main__.py
スクリプトを実行できる場合は、上記のセットアップを使用します。次に、from Package import ...
ステートメントがまだ成功していることを確認する必要があります。これは、インポートパスを拡張することで実現できます(これには、src
ディレクトリの名前をパッケージ名に変更する必要があります!)。
PYTHONPATH
を変更Linux bashの場合、次のようにPythonpathを設定できます。
export PYTHONPATH=$PYTHONPATH:/path/to/Package
または、__main__.py
と同じディレクトリにいる場合:
export PYTHONPATH=$PYTHONPATH:`cd ..; pwd`
もちろん、オペレーティングシステムごとに異なる方法があります。
__main__.py
のパスを拡張しますあなた(またはあなたの同僚)は、スクリプトの先頭(from Package import ...
ステートメントの前)に次の行を追加できます。
import sys
sys.path.append('/path/to/Package')
sitecustomize.py
のパスを拡張します次の行を含むPythonインストールのsitecustomize.py
ディレクトリに lib/python3.5/site-packages/
という名前のモジュールを配置できます。
import sys
sys.path.append('/path/to/Package')
main.py
スクリプトを作成しますしたがって、次のレイアウトになります。
$ tree Package/
Package/
├── main.py <-- Add this file.
├── setup.py
└── src
├── code.py
├── __init__.py
└── __main__.py
main.py
には次が含まれます
import src.__main__
これで__main__.py
はsrc
パッケージの一部として扱われ、相対インポートが機能します。 python src/__main__.py
を実行する代わりに、今すぐpython main.py
を実行します。
code
という名前のシステムにPythonパッケージがインストールされていないため、from code import .........
は失敗します。 code
という名前のシステムにはPython moduleがありますが、importステートメントではcode
モジュールのパッケージを指定しませんで見つけることができます。
__init__.py
にあるsrc/
ファイルの目的は、src/
ディレクトリをPythonパッケージとして処理する必要があることをPythonに伝えますパッケージ内のモジュールとしてのコンテンツ。 code.py
はsrc/
ファイルと共に__init__.py
にあるため、code
モジュールはsrc
パッケージにあります。
code
モジュールがどのパッケージにあるかがわかったので、次のものを使用してそこからものをインポートできます。
from src.code import .........
また、補足として:__init__.py
はsrc/
ディレクトリに存在するだけで機能するため、コードを含める必要さえありません。そのため、__init__.py
ファイルを空白のままにしておくことをお勧めします。
このセットアップは、python setup.py develop
Package_root/
setup.py
src/
Package/
__init__.py
__main__.py
code.py
それはおそらく(まだ)あなたが期待している詳細な答えではありませんが、3つのユースケースに挑戦する価値があると思います。
setup( ...
package_dir = {'': 'src'},
entry_points = {'console_scripts': ['Package = Package.__main__:main'],},
packages = find_packages(exclude=["Package.Egg_info",]),
...)