私はここにいました:
コピーしなかったURLもたくさんあります。SOにあるものもあれば、他のサイトにあるものもあります。すぐに解決策があると思ったときです。
永遠に繰り返される質問はこれです:Windows 7、32ビットPython 2.7.3で、この「非パッケージでの相対インポートの試行」メッセージを解決するにはどうすればよいですか?私はpep-0328でパッケージの正確なレプリカを作成しました:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
インポートはコンソールから行われました。
適切なモジュールでspamとeggsという名前の関数を作成しました。当然、それは機能しませんでした。答えは明らかに私がリストした4番目のURLにありますが、それはすべて私にとって卒業生です。私がアクセスしたURLの1つにこの応答がありました:
相対インポートでは、モジュールのname属性を使用して、パッケージ階層内でのそのモジュールの位置を決定します。モジュールの名前にパッケージ情報が含まれていない場合(たとえば、「main」に設定されている場合)、相対インポートは、モジュールがファイルシステムの実際の場所にあるかどうかに関係なく、モジュールが最上位モジュールであるかのように解決されます。
上記の応答は有望に見えますが、それはすべて私には象形文字です。だから私の質問は、Pythonが「非パッケージで相対インポートを試みた」というメッセージを返さないようにするにはどうすればよいですか?おそらく-mを含む答えがあります。
Pythonがそのエラーメッセージを表示する理由、「非パッケージ」の意味、「パッケージ」を定義する理由と方法、幼稚園児が理解しやすい言葉で正確な答えを教えてください。
スクリプトとモジュール
これが説明です。短いバージョンでは、Pythonファイルを直接実行することと、そのファイルを別の場所からインポートすることには大きな違いがあります。ファイルがどのディレクトリにあるかを知っているだけでは、Pythonがどのパッケージにあると見なすかは決まりません。さらに、ファイルをPythonにロードする方法(実行またはインポート)によって異なります。
Pythonファイルをロードするには、トップレベルのスクリプトとして、またはモジュールとして2つの方法があります。ファイルはpython myfile.py
、コマンドラインで入力するなどして直接実行すると、最上位のスクリプトとして読み込まれます。を実行した場合python -m myfile
、またはimport
他のファイル内でステートメントが検出されたときにロードされた場合は、モジュールとしてロードされます。一度に存在できるトップレベルスクリプトは1つだけです。トップレベルのスクリプトは、最初に実行したPythonファイルです。
ネーミング
ファイルがロードされると、名前が付けられます(これはその__name__
属性に格納されます)。トップレベルスクリプトとしてロードされた場合、その名前は__main__
です。モジュールとしてロードされた場合、その名前はファイル名であり、その前に、ドットで区切られた、その一部であるパッケージ/サブパッケージの名前が続きます。
したがって、たとえばあなたの例では:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
インポートした場合moduleX
(注:インポートされた、直接実行されない)、その名前はpackage.subpackage1.moduleX
。インポートした場合moduleA
、その名前はになりますpackage.moduleA
。ただし、コマンドラインから直接実行する 場合moduleX
、その名前は代わりにになり__main__
、moduleA
コマンドラインから直接実行する場合、その名前はになります__main__
。モジュールがトップレベルのスクリプトとして実行されると、通常の名前は失われ、代わりにその名前がになり__main__
ます。
含まれているパッケージを介さずにモジュールにアクセスする
追加のしわがあります。モジュールの名前は、モジュールが含まれているディレクトリから「直接」インポートされたか、パッケージを介してインポートされたかによって異なります。これは、ディレクトリでPythonを実行し、同じディレクトリ(またはそのサブディレクトリ)にファイルをインポートしようとした場合にのみ違いがあります。たとえば、あなたがディレクトリにPythonインタプリタを起動した場合package/subpackage1
、次に行うimport moduleX
の名前はmoduleX
ちょうどになりmoduleX
、そしてませんpackage.subpackage1.moduleX
。これは、Pythonが起動時に現在のディレクトリを検索パスに追加するためです。現在のディレクトリでインポートするモジュールが見つかった場合、そのディレクトリがパッケージの一部であることがわかりません。また、パッケージ情報はモジュール名の一部にはなりません。
特別な場合は、インタプリタをインタラクティブに実行する場合です(たとえば、python
Pythonコードをその場で入力して入力を開始するだけです)。この場合、その対話型セッションの名前は__main__
です。
ここで、エラーメッセージにとって重要なことがあります。モジュールの名前にドットがない場合、それはパッケージの一部とは見なされません。ファイルが実際にディスク上のどこにあるかは関係ありません。重要なのはその名前が何であるかであり、その名前はロードした方法によって異なります。
次に、質問に含めた見積もりを見てください。
相対インポートでは、モジュールのname属性を使用して、パッケージ階層内でのそのモジュールの位置を決定します。モジュールの名前にパッケージ情報が含まれていない場合(たとえば、「main」に設定されている場合)、相対インポートは、モジュールがファイルシステムの実際の場所にあるかどうかに関係なく、モジュールが最上位モジュールであるかのように解決されます。
相対輸入...
相対インポートでは、モジュールの名前を使用して、モジュールがパッケージ内のどこにあるかを判別します。のような相対インポートを使用する場合from .. import foo
、ドットはパッケージ階層内のいくつかのレベルをステップアップすることを示します。たとえば、現在のモジュールの名前がpackage.subpackage1.moduleX
、の場合、..moduleA
はを意味しpackage.moduleA
ます。が機能するためにはfrom .. import
、モジュールの名前に少なくともimport
ステートメントにあるのと同じ数のドットが含まれている必要があります。
...パッケージ内の相対的なもののみ
ただし、モジュールの名前が__main__
、の場合、パッケージに含まれているとは見なされません。その名前にはドットがないため、そのfrom .. import
中でステートメントを使用することはできません。これを行おうとすると、「パッケージ以外の相対インポート」エラーが発生します。
スクリプトは相対をインポートできません
おそらくあなたがしたことはmoduleX
、コマンドラインから実行しようとしたことなどです。これを行うと、その名前はに設定されました。これは、その名前が__main__
パッケージ内にあることを明らかにしないため、その名前内の相対インポートが失敗することを意味します。これは、モジュールと同じディレクトリからPythonを実行し、そのモジュールをインポートしようとした場合にも発生することに注意してください。上記のように、Pythonは現在のディレクトリでモジュールを「早すぎる」と認識せずに検出するためです。パッケージの一部。
また、対話型インタプリタを実行する場合、その対話型セッションの「名前」は常にであることに注意してください__main__
。したがって、インタラクティブセッションから直接相対インポートを行うことはできません。相対インポートは、モジュールファイル内でのみ使用されます。
2つの解決策:
本当にmoduleX
直接実行したいが、それでもパッケージの一部と見なしたい場合は、を実行できますpython -m package.subpackage1.moduleX
。-m
ないトップレベルのスクリプトとして、モジュールとしてロードするためのPythonに指示します。
または、実際には実行し たくない場合は、内部の関数を使用するmoduleX
他のスクリプトを実行したいだけです。その場合は、入れてどこか-ではない内部のディレクトリ-と、それを実行します。内部でのようなことをすれば、それはうまくいくでしょう。myfile.py
moduleX
myfile.py
package
myfile.py
from package.moduleA import spam
ノート
これらのソリューションのいずれの場合も、パッケージディレクトリ(このpackage
例では)はPythonモジュールの検索パス(sys.path
)からアクセスできる必要があります。そうでない場合、パッケージ内の何も確実に使用することはできません。
Python 2.6以降、パッケージ解決を目的としたモジュールの「名前」は、その__name__
属性だけでなく、__package__
属性によっても決定されます。その__name__
ため、モジュールの「名前」を参照するために明示的な記号を使用することは避けています。Python 2.6以降、モジュールの「名前」は事実上__package__ + '.' + __name__
、またはそうである__name__
場合に限り__package__
ますNone
。)
これは本当にPython内の問題です。混乱の原因は、人々が誤って相対的なインポートをパスの相対的なものと見なしていないことです。
たとえば、faa.pyに書き込む場合:
from .. import foo
これは、実行中にPythonによってfaa.pyがパッケージの一部として識別され、ロードされた場合にのみ意味があります。その場合、faa.pyのモジュール名は、たとえばsome_packagename.faaになります。ファイルが現在のディレクトリにあるという理由だけでロードされた場合、Pythonを実行すると、その名前はパッケージを参照せず、最終的に相対インポートは失敗します。
現在のディレクトリ内のモジュールを参照する簡単な解決策は、これを使用することです。
if __package__ is None or __package__ == '':
# uses current directory visibility
import foo
else:
# uses current package visibility
from . import foo
これは、例として適合するように変更された一般的なレシピです。パッケージとして記述されたPythonライブラリを処理するために現在使用しています。このライブラリには、相互依存ファイルが含まれており、それらの一部を少しずつテストできるようにします。さんはこれを呼ぶことにしましょうlib.foo
、それはへのアクセスを必要としていることを言うlib.fileA
な機能のためにf1
とf2
、そしてlib.fileB
クラスClass3
。
これがprint
どのように機能するかを説明するために、いくつかの呼び出しを含めました。実際には、それら(およびおそらくfrom __future__ import print_function
行も)を削除する必要があります。
この特定の例は単純すぎて、本当にエントリをに挿入する必要がある場合を示すことができませんsys.path
。(参照ラースと答えた私たちはケースのためか、我々はパッケージディレクトリの2つ以上のレベルを持っている場合、それを必要とし、その後、我々が使用するos.path.dirname(os.path.dirname(__file__))
ことが本当にありません-ブタ傷つけることもなく、これを行うには、安全なだけで十分ですどちらかここに。)if _i in sys.path
テスト。ただし、インポートされた各ファイルが同じパスを挿入する場合(たとえば、両方fileA
でfileB
ユーティリティをパッケージからインポートする場合)、これsys.path
は同じパスで何度も混乱するためif _i not in sys.path
、ボイラープレートにを含めると便利です。
from __future__ import print_function # only when showing how this works
if __package__:
print('Package named {!r}; __name__ is {!r}'.format(__package__, __name__))
from .fileA import f1, f2
from .fileB import Class3
else:
print('Not a package; __name__ is {!r}'.format(__name__))
# these next steps should be used only with care and if needed
# (remove the sys.path manipulation for simple cases!)
import os, sys
_i = os.path.dirname(os.path.abspath(__file__))
if _i not in sys.path:
print('inserting {!r} into sys.path'.format(_i))
sys.path.insert(0, _i)
else:
print('{!r} is already in sys.path'.format(_i))
del _i # clean up global name space
from fileA import f1, f2
from fileB import Class3
... all the code as usual ...
if __name__ == '__main__':
import doctest, sys
ret = doctest.testmod()
sys.exit(0 if ret.failed == 0 else 1)
ここでの考え方はこれです(そしてこれらはすべてpython2.7とpython 3.xで同じように機能することに注意してください):
通常のコードからの通常のパッケージインポートとして、import lib
またはfrom lib import foo
通常のパッケージとして実行する場合、__package
islib
および__name__
islib.foo
です。最初のコードパスを取得し、からインポートします.fileA
。
として実行するとpython lib/foo.py
、__package__
Noneになり、に__name__
なります__main__
。
2番目のコードパスを使用します。lib
ディレクトリはすでにになりsys.path
、それを追加する必要はありませんので。fileA
等から輸入しております。
lib
としてディレクトリ内で実行した場合python foo.py
、動作はケース2の場合と同じです。
lib
としてディレクトリ内で実行した場合python -m foo
、動作はケース2および3と同様です。ただし、lib
ディレクトリへのパスはにないsys.path
ため、インポートする前に追加します。Pythonを実行してからimport foo
。
以来(.
ある中でsys.path
、私たちは本当にここで、パスの絶対的なバージョンを追加する必要はありません。私たちがやりたい、より深いパッケージの入れ子構造が、ここはfrom ..otherlib.fileC import ...
、違いになります。あなたはこれをやっていない場合、あなたがすることができますすべてのsys.path
操作を完全に省略します。)
まだ癖があります。このすべてを外部から実行する場合:
$ python2 lib.foo
または:
$ python3 lib.foo
動作はの内容によって異なりlib/__init__.py
ます。それが存在し、空の場合、すべてが順調です。
Package named 'lib'; __name__ is '__main__'
しかし、lib/__init__.py
それ自体がインポートしroutine
て、routine.name
として直接エクスポートできる場合はlib.name
、次のようになります。
$ python2 lib.foo
Package named 'lib'; __name__ is 'lib.foo'
Package named 'lib'; __name__ is '__main__'
つまり、モジュールは2回インポートされます。1回はパッケージを介してインポートされ、もう1回はコードを__main__
実行するためにインポートされmain
ます。Python 3.6以降では、これについて警告しています。
$ python3 lib.routine
Package named 'lib'; __name__ is 'lib.foo'
[...]/runpy.py:125: RuntimeWarning: 'lib.foo' found in sys.modules
after import of package 'lib', but prior to execution of 'lib.foo';
this may result in unpredictable behaviour
warn(RuntimeWarning(msg))
Package named 'lib'; __name__ is '__main__'
警告は新しいですが、警告し-について動作ではありません。これは、ダブルインポートトラップと呼ばれるものの一部です。(詳細については、問題27487を参照してください。)NickCoghlanは次のように述べています。
この次のトラップは、3.3を含む現在のすべてのバージョンのPythonに存在し、次の一般的なガイドラインにまとめることができます。「パッケージディレクトリまたはパッケージ内のディレクトリをPythonパスに直接追加しないでください」。
注ここではそのルールに違反している間、我々はそれを行うことのみロードされたファイルがされていないパッケージの一部としてロードされている、と私たちの修正は、具体的に私たちは、そのパッケージ内の他のファイルへのアクセスを許可するように設計されています。(そして、私が述べたように、おそらく単一レベルのパッケージに対してこれを行うべきではありません。)余分にクリーンにしたい場合は、これを次のように書き直すことができます。
import os, sys
_i = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if _i not in sys.path:
sys.path.insert(0, _i)
else:
_i = None
from sub.fileA import f1, f2
from sub.fileB import Class3
if _i:
sys.path.remove(_i)
del _i
つまりsys.path
、インポートを実行するのに十分な時間変更してから、元の状態に戻します(1つのコピー_i
を追加した場合にのみ1つのコピーを削除します_i
)。
それで、他の多くの人たちと一緒にこれについて考えた後、私はこの記事でドリアンBによって投稿された、Webサービスで使用するモジュールとクラスを開発する場所で私が抱えていた特定の問題を解決したメモに出くわしましたが、 PyCharmのデバッガー機能を使用して、コーディング中にそれらをテストできます。自己完結型のクラスでテストを実行するには、クラスファイルの最後に次のものを含めます。
if __name__ == '__main__':
# run test code here...
しかし、同じフォルダーに他のクラスやモジュールをインポートしたい場合は、すべてのインポートステートメントを相対表記からローカル参照に変更する必要があります(つまり、ドット(。)を削除します)。しかし、ドリアンの提案を読んだ後、彼の 'を試しました。ワンライナー」とそれはうまくいきました!これで、PyCharmでテストして、テスト対象の別のクラスでクラスを使用するとき、またはWebサービスで使用するときに、テストコードをそのままにしておくことができます。
# import any site-lib modules first, then...
import sys
parent_module = sys.modules['.'.join(__name__.split('.')[:-1]) or '__main__']
if __name__ == '__main__' or parent_module.__name__ == '__main__':
from codex import Codex # these are in same folder as module under test!
from dblogger import DbLogger
else:
from .codex import Codex
from .dblogger import DbLogger
ifステートメントは、このモジュールをmainとして実行しているかどうか、またはmainとしてテストされている別のモジュールで使用されているかどうかを確認します。おそらくこれは明らかですが、上記の相対的なインポートの問題に不満を持っている人がそれを利用できる場合に備えて、ここでこのメモを提供します。
これは私がお勧めしない1つの解決策ですが、モジュールが単に生成されなかったいくつかの状況で役立つかもしれません:
import os
import sys
parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(parent_dir_name + "/your_dir")
import your_script
your_script.a_function()
Pythonモジュールの検索パスを変更したくなく、スクリプトから比較的モジュールをロードする必要があるという同様の問題がありました(BrenBarnが上でうまく説明したように、「スクリプトはすべてに対して相対をインポートできない」にもかかわらず)。
そこで、次のハックを使用しました。残念ながら、imp
バージョン3.4以降で非推奨になったモジュールに依存して、を優先して削除されimportlib
ます。(これも可能importlib
ですか?わかりません。)それでも、ハックは今のところ機能します。
フォルダにあるスクリプトからmoduleX
inのメンバーにアクセスする例:subpackage1
subpackage2
#!/usr/bin/env python3
import inspect
import imp
import os
def get_script_dir(follow_symlinks=True):
"""
Return directory of code defining this very function.
Should work from a module as well as from a script.
"""
script_path = inspect.getabsfile(get_script_dir)
if follow_symlinks:
script_path = os.path.realpath(script_path)
return os.path.dirname(script_path)
# loading the module (hack, relying on deprecated imp-module)
PARENT_PATH = os.path.dirname(get_script_dir())
(x_file, x_path, x_desc) = imp.find_module('moduleX', [PARENT_PATH+'/'+'subpackage1'])
module_x = imp.load_module('subpackage1.moduleX', x_file, x_path, x_desc)
# importing a function and a value
function = module_x.my_function
VALUE = module_x.MY_CONST
よりクリーンなアプローチは、Federicoが述べたように、モジュールのロードに使用されるsys.pathを変更することのようです。
#!/usr/bin/env python3
if __name__ == '__main__' and __package__ is None:
from os import sys, path
# __file__ should be defined in this case
PARENT_DIR = path.dirname(path.dirname(path.abspath(__file__)))
sys.path.append(PARENT_DIR)
from subpackage1.moduleX import *
__name__
問題のコードがグローバル名前空間で実行されているか、インポートされたモジュールの一部として実行されているかによって異なります。
コードがグローバルスペースで実行されていない場合__name__
は、モジュールの名前になります。グローバル名前空間で実行されている場合(たとえば、コンソールに入力する場合、またはを使用してモジュールをスクリプトとして実行する場合)はpython.exe yourscriptnamehere.py
、に__name__
なり"__main__"
ます。
if __name__ == '__main__'
コードがグローバル名前空間から実行されているかどうかをテストするために使用される多くのPythonコードが表示されます。これにより、スクリプトを兼ねるモジュールを作成できます。
コンソールからこれらのインポートを実行しようとしましたか?
@BrenBarnの答えはすべてを物語っていますが、あなたが私のようであれば、理解するのに時間がかかるかもしれません。これが私の場合と@BrenBarnの答えがそれにどのように当てはまるかです。おそらくそれはあなたを助けるでしょう。
ケース
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
おなじみの例を使用して、moduleX.pyが..moduleAへの相対インポートを持っていることを追加します。moduleXをインポートしたsubpackage1ディレクトリにテストスクリプトを書き込もうとしましたが、OPによって記述された恐ろしいエラーが発生しました。
解決
テストスクリプトをパッケージと同じレベルに移動し、package.subpackage1.moduleXをインポートします
説明
説明したように、相対インポートは現在の名前を基準にして行われます。テストスクリプトが同じディレクトリからmoduleXをインポートする場合、moduleX内のモジュール名はmoduleXです。相対インポートが発生すると、インタプリタはすでに最上位にあるため、パッケージ階層をバックアップできません。
上からmoduleXをインポートすると、moduleX内の名前はpackage.subpackage1.moduleXになり、相対的なインポートを見つけることができます。
相対インポートでは、モジュールのname属性を使用して、パッケージ階層内でのそのモジュールの位置を決定します。モジュールの名前にパッケージ情報が含まれていない場合(たとえば、「main」に設定されている場合)、相対インポートは、モジュールがファイルシステムの実際の場所にあるかどうかに関係なく、モジュールが最上位モジュールであるかのように解決されます。
この質問の視聴者を助けるかもしれない小さなpythonパッケージをPyPiに書きました。パッケージは、インポートファイルのディレクトリに直接移動することなく、パッケージ/プロジェクト内から上位レベルのパッケージを含むインポートを含むPythonファイルを実行できるようにする場合の回避策として機能します。https://pypi.org/project/import-anywhere/
別の汚いが回避策。あなたがあなたのパッケージのトップレベルにいると仮定します。
import sys
from os.path import dirname, basename
if __package__ is None:
sys.path.append('..')
__package__ = basename(dirname(sys.argv[0]))
from . import your_module
ここでの利点と別の答えは、IDEによって自動生成されるインポートを変更する必要がないことです。
特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。
ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。
ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。
ジョー・バロウロー対ウェイド事件の転覆に対応するNFLは、言葉を言わないことで、腹立たしいが予測可能なPRの結果でした。
(lから)パット・ペレス、ブルックス・ケプカ、パトリック・リードサウジアラビアのLIVゴルフリーグのさらに別の信じられないほどの記者会見で、スポーツのファンはブルックス・ケプカからでたらめな吐き気と質問回避の驚異的なマスタークラスを受けました。パトリックリード、ブライソンデシャンボー、パットペレス、最近のPGAツアーの脱北者。
暗号業界最大の沈没船の1つであるスリーアローズキャピタルは、ついにその悲惨さから解放されています。火曜日に、不良債権ヘッジファンドは、債権者からの返済を要求する訴訟の高まりに応えて、バージンアイランド裁判所によって清算を命じられました彼らが3ACに行ったローン。
Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday
シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。
オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。
Mais um mês se findando — e metade do ano de 2022 já passou. Sabe o que isso significa? Não, não é hora de verificar se você está cumprindo com suas resoluções de Ano Novo.
1.ドラマを見た後、起業する考えはありますか?あなたのビジネスはボトルネックに遭遇しましたか?方向性がなくてわからない場合は、ドラマを追いかけて行くことを心からお勧めします。(?)ブラフではなく、最も完璧なビジネス例を隠すドラマがあります。2.ブレイキング・バッドとその弁護士ドラマ「ブレイキング・バッド」を見た友人たちは、演劇の中で、穏やかな表情で、弁護士のソウル・グッドマンに深く感銘を受けなければなりません。口を開けて、感覚の弱い傭兵の性格を持っています。道徳の面で、サル・グッドマンは無意識のうちに劇に欠かせない役割を果たし、彼自身のシリーズ「絶望的な弁護士」(ベター・コール・ソール)を生み出しました。ウェントウのテキストとビデオは、劇中のソウル・グッドマンのテレビコマーシャルです。製品(サービス)、競争戦略、市場ポジショニング、ブランド名、ターゲット顧客グループ、コミュニケーション軸から広告まで、サル・グッドマンの役割のビジネス設定は、「最低」と見なすことができる超超超超超超完全です。ブランドコミュニケーションのコスト」「変化」のモデル。なぜ?私の分析をご覧ください。3.ソウル・グッドマンの「事業戦略」1.基本情報ブランド名:Saul Goodman製品:法律相談サービス対象顧客:麻薬中毒、飲酒運転、事故など。法律知識の欠如は、一般的に公立弁護士にしか余裕がなく、真面目な弁護士も「特別な法律を持つ消費者」を避けます。恐れてはいけない「ニーズ」。コミュニケーションの主軸:この国のすべての男性、女性、子供は有罪判決を受けるまで無実だと思います。地域:アルバカーキ市スローガン:Thrallに電話したほうがいいです!(ベター・コール・ソール)広告:2つの可能性のある犯罪状況をシミュレートします+サウルの主張+サウルのスローガン2をより適切に呼び出します。