同じディレクトリ内の別のファイルから関数をインポートしたいのですが。
時にはそれはfrom .mymodule import myfunction
で私のために働くが、時々私は得る:
SystemError: Parent module '' not loaded, cannot perform relative import
時にはそれはfrom mymodule import myfunction
で動作しますが、時々私はまた得る:
SystemError: Parent module '' not loaded, cannot perform relative import
私はここで論理を理解していません、そして私は説明を見つけることができませんでした。これは完全にランダムに見えます。
誰かが私にこれすべての背後にある論理は何ですか説明してもらえますか?
残念ながら、このモジュールはパッケージ内にある必要があります。また、場合によってはスクリプトとして実行できる必要もあります。どうすればそれを達成できますか?
このようなレイアウトを持つことは非常に一般的です...
main.py
mypackage/
__init__.py
mymodule.py
myothermodule.py
...このようなmymodule.py
で...
#!/usr/bin/env python3
# Exported function
def as_int(a):
return int(a)
# Test function for module
def _test():
assert as_int('1') == 1
if __== '__main__':
_test()
...myothermodule.py
このように...
#!/usr/bin/env python3
from .mymodule import as_int
# Exported function
def add(a, b):
return as_int(a) + as_int(b)
# Test function for module
def _test():
assert add('1', '1') == 2
if __== '__main__':
_test()
...およびmain.py
は次のようになります...
#!/usr/bin/env python3
from mypackage.myothermodule import add
def main():
print(add('1', '1'))
if __== '__main__':
main()
...main.py
またはmypackage/mymodule.py
を実行すると正常に動作しますが、相対的なインポートのためにmypackage/myothermodule.py
で失敗します...
from .mymodule import as_int
あなたがそれを実行することになっている方法は...
python3 -m mypackage.myothermodule
...しかし、それはいくぶん冗長で、#!/usr/bin/env python3
のようなシバン行とうまく混ざりません。
この場合の最も簡単な修正は、名前mymodule
がグローバルに一意であると仮定して、相対インポートの使用を避け、単に使用することです...
from mymodule import as_int
...ただし、一意ではない場合、またはパッケージ構造がより複雑な場合は、パッケージディレクトリを含むディレクトリをPYTHONPATH
に含めて、このようにする必要があります...
from mypackage.mymodule import as_int
...または「そのまま使用」したい場合は、最初にコードでPYTHONPATH
をフロブすることができます...
import sys
import os
PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))
from mypackage.mymodule import as_int
ちょっとした痛みですが、なぜ 電子メール に特定のGuido van Rossumが書いたのかについての手がかりがあります...
私はこれと
__main__
機械の他の提案された調整について-1です。唯一のユースケースは、モジュールのディレクトリ内に存在するスクリプトを実行することであるように思われますが、これは常にアンチパターンと見なされてきました。私の考えを変えさせるには、そうではないことを私に納得させる必要があります。
パッケージ内でスクリプトを実行するのがアンチパターンであるかどうかは主観的ですが、個人的には、いくつかのカスタムwxPythonウィジェットを含むパッケージで本当に便利なので、ソースファイルのいずれかに対してスクリプトを実行してwx.Frame
テスト目的のウィジェットのみを含む。
これをあなたのパッケージの__init__.pyファイルの中に入れてください :
# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))
あなたのパッケージがこのようになっていると仮定します。
├── project
│ ├── package
│ │ ├── __init__.py
│ │ ├── module1.py
│ │ └── module2.py
│ └── setup.py
以下のように、パッケージ内で通常のインポートを使用します。
# in module2.py
from module1 import class1
これはpython 2と3の両方で動作します。
私はこの問題に遭遇しました。ハックの回避策は、次のようにif/elseブロックを介してインポートすることです。
#!/usr/bin/env python3
#myothermodule
if __== '__main__':
from mymodule import as_int
else:
from .mymodule import as_int
# Exported function
def add(a, b):
return as_int(a) + as_int(b)
# Test function for module
def _test():
assert add('1', '1') == 2
if __== '__main__':
_test()
うまくいけば、これはそこに誰かに価値があるでしょう - 私はここに上に掲載されたものと同様の相対的な輸入を把握しようとしている半ダースstackoverflowの投稿を見ました。提案どおりにすべてを設定しましたが、まだModuleNotFoundError: No module named 'my_module_name'
を打っていました
私はローカルで開発して遊んでいるだけなので、私はsetup.py
ファイルを作成/実行していませんでした。私はまた、どうやら私のPYTHONPATH
を設定していませんでした。
テストがモジュールと同じディレクトリにあったときと同じようにコードを実行したときに、自分のモジュールが見つからないことに気付きました。
$ python3 test/my_module/module_test.py 2.4.0
Traceback (most recent call last):
File "test/my_module/module_test.py", line 6, in <module>
from my_module.module import *
ModuleNotFoundError: No module named 'my_module'
しかし、私が明示的にパスを指定したとき、ものが動き始めました:
$ PYTHONPATH=. python3 test/my_module/module_test.py 2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s
OK
したがって、誰かがいくつかの提案を試みた場合、自分のコードが正しく構造化されていて、現在のディレクトリをPYTHONPATHにエクスポートしないと、私自身が次のいずれかを試みるのと同じ状況にあると考えます。
$ PYTHONPATH=. python3 test/my_module/module_test.py
PYTHONPATH=.
を呼び出さないようにするには、次のような内容のsetup.py
ファイルを作成し、python setup.py development
を実行してパッケージをパスに追加します。# setup.py from setuptools import setup, find_packages setup( name='sample', packages=find_packages() )
この問題を回避するために、私は repackage パッケージを使って解決策を考案しました。それはlibパスに上位ディレクトリを追加します。
import repackage
repackage.up()
from mypackage.mymodule import myfunction
再パッケージ化では、インテリジェントな戦略(コールスタックの検査)を使用して、さまざまなケースで機能する相対インポートを実行できます。
私はそれを動作させるためにメインプロジェクトディレクトリからpython3を実行する必要がありました。
たとえば、プロジェクトが次のような構造になっているとします。
project_demo/
├── main.py
├── some_package/
│ ├── __init__.py
│ └── project_configs.py
└── test/
└── test_project_configs.py
Python3をフォルダ project_demo/ の中で実行してから、
from some_package import project_configs
両方のパッケージがあなたのインポートパス(sys.path)にあり、あなたが欲しいモジュール/クラスがexample/example.pyにあるなら、相対インポートなしでクラスにアクセスするために試してみてください:
from example.example import fkt