10億回目の相対的な輸入


716

私はここにいます:

そして、私がすぐに解決策を手に入れたいと思ったとき、私がコピーしなかったたくさんの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とeggという名前の関数を適切なモジュールで作成しました。当然、うまくいきませんでした。答えは、私がリストした4番目のURLにあるようですが、それはすべて同窓生です。私がアクセスしたURLの1つにこの応答がありました:

相対インポートは、モジュールの名前属性を使用して、パッケージ階層におけるそのモジュールの位置を決定します。モジュールの名前にパッケージ情報が含まれていない場合(「メイン」に設定されているなど)、相対インポートは、モジュールが実際にファイルシステムのどこに配置されているかに関係なく、モジュールが最上位モジュールであるかのように解決されます。

上記の応答は有望に見えますが、私にとってはすべての象形文字です。それで私の質問、Pythonが「非パッケージで試行された相対インポート」を返さないようにするにはどうすればよいですか?おそらく-mを含む答えがあります。

Pythonがエラーメッセージを表示する理由、「非パッケージ」の意味、「パッケージ」を定義する理由と方法、幼稚園児が理解しやすいように正確な答えを教えてください。


5
表示したファイルをどのように使用しようとしていますか?実行しているコードは何ですか?
BrenBarn 2013年

python.org/dev/peps/pep-0328を参照してください。投稿で説明したパッケージ形式を使用しました。初期化の.pyファイルは空です。moduleY.pyはdef spam(): pass、moduleA.pyはを持っていdef eggs(): passます。「from .something import something」コマンドをいくつか実行しようとしましたが、機能しませんでした。再度、pep-0328を参照してください。

6
私の答えを見てください。あなたはまだあなたが何をしているのかを完全に明らかにしていませんfrom .something import somethingが、インタラクティブなインタープリターでやろうとしてもうまくいきません。相対インポートはモジュール内でのみ使用でき、インタラクティブには使用できません。
BrenBarn 2013年

105
「何十億」という人々(このコメントの時点では83,136で大丈夫)が、この質問を検索するのに十分なインポートの困難を抱えているという単なる事実。ほとんどではないにしても、多くのプログラマにとって、Pythonのインポートは直感に反するものであると結論付けることしかできません。グイド、おそらくこれを受け入れ、委員会にインポートメカニズムの再設計を依頼する必要があります。少なくとも、x.pyとz.pyが同じディレクトリにある場合、この構文は機能するはずです。つまり、x.pyにステートメントがある場合、 "from .z import MyZebraClass" xは、メインとして実行されている場合でもzをインポートする必要があります。なぜそんなに難しいのですか?
スティーブL

4
このスレッドの大部分を読んだ後、質問への回答ではありませんが、「絶対インポートを使用する」が解決策のようです...
CodeJockey

回答:


1043

スクリプトとモジュール

ここに説明があります。短いバージョンは、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__です。

エラーメッセージの重要な点は次のとおりです。モジュールの名前にドットがない場合、パッケージの一部とは見なされません。ファイルが実際にディスク上のどこにあってもかまいません。重要なのはその名前が何であるかであり、その名前はロード方法によって異なります。

次に、質問に含めた引用を見てください。

相対インポートは、モジュールの名前属性を使用して、パッケージ階層におけるそのモジュールの位置を決定します。モジュールの名前にパッケージ情報が含まれていない場合(「メイン」に設定されているなど)、相対インポートは、モジュールが実際にファイルシステムのどこに配置されているかに関係なく、モジュールが最上位モジュールであるかのように解決されます。

相対インポート...

相対インポートは、モジュールの名前を使用して、パッケージ内のどこにあるかを判別します。のような相対インポートを使用する場合from .. import foo、ドットは、パッケージ階層のいくつかのレベルを上げることを示します。たとえば、現在のモジュールの名前がのpackage.subpackage1.moduleX場合、..moduleAはを意味しpackage.moduleAます。以下のためfrom .. importにあるような作業に、モジュールの名前が、少なくとも多くのドットとして持っている必要がありますimport声明。

...パッケージ内でのみ相対的

ただし、モジュールの名前が__main__である場合、パッケージ内にあるとは見なされません。その名前にはドットがないため、そのfrom .. import中でステートメントを使用することはできません。そうしようとすると、「非パッケージ内の相対インポート」エラーが発生します。

スクリプトは相対をインポートできません

おそらくあなたがしたことはmoduleX、コマンドラインから実行しようとしたことなどです。これを行ったとき、その名前はに設定されて__main__いました。つまり、その名前ではパッケージ内にあることが明らかにならないため、その内部での相対的なインポートは失敗します。これは、モジュールがあるのと同じディレクトリからPythonを実行し、そのモジュールをインポートしようとした場合にも発生することに注意してください。これは、前述のように、Pythonが現在のディレクトリでモジュールを「早すぎる」と認識しないためです。パッケージの一部。

また、インタラクティブインタープリタを実行すると、そのインタラクティブセッションの「名前」は常にになり__main__ます。したがって、対話型セッションから直接相対インポートを行うことはできません。相対インポートは、モジュールファイル内でのみ使用できます。

2つのソリューション:

  1. 本当にmoduleX直接実行したいが、それでもパッケージの一部と見なしたい場合は、実行できますpython -m package.subpackage1.moduleX-mないトップレベルのスクリプトとして、モジュールとしてロードするためのPythonに指示します。

  2. あるいは、実際には実行し たくない場合は、内部の関数を使用するmoduleX他のスクリプトを実行したいだけかもしれません。その場合は、入れてどこか - ではない内部のディレクトリ-と、それを実行します。内部でのようなことをすると、それはうまくいきます。myfile.pymoduleXmyfile.py packagemyfile.pyfrom package.moduleA import spam

ノート

  • これらのソリューションのどちらでも、パッケージディレクトリ(package例では)はPythonモジュールの検索パス(sys.path)からアクセスできる必要があります。そうでない場合、パッケージ内の何も確実に使用できなくなります。

  • Python 2.6以降、パッケージ解決のためのモジュールの「名前」は、その__name__属性だけでなく属性によっても決まり__package__ます。そのため、明示的なシンボル__name__を使用してモジュールの「名前」を参照することは避けています。Python 2.6以降、モジュールの「名前」は事実上__package__ + '.' + __name__、またはの__name__場合のみ__package__ですNone。)


62
Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the "relative-import in non-package" error.これは根本的に不安です。現在のディレクトリを見ることの何がそんなに難しいのですか?Pythonはこれに対応できる必要があります。これはバージョン3xで修正されていますか?

7
@Stopforgettingmyaccounts ...:PEP 366はその仕組みを示しています。ファイルの中で、あなたはそうすることができます__package__ = 'package.subpackage1'。その場合、直接実行した場合でも、そのファイルのみ常にそのパッケージの一部と見なされます。__package__ここで元の質問の問題を解決するため、他に質問がある場合は別の質問をすることをお勧めします。
BrenBarn 2013年

108
これは、すべてのPython相対インポートの質問に対する答えになるはずです。これもドキュメントにあるはずです。
edsioufi 2014年

10
python.org/dev/peps/pep-0366を参照してください-「このボイラープレートは、最上位パッケージがsys.pathを介してすでにアクセス可能な場合にのみ十分であることに注意してください。直接実行するには、sys.pathを操作する追加コードが必要です。最上位のパッケージがすでにインポート可能でなくても動作するようにします。」-この「追加コード」は実際には非常に長く、パッケージ内の他の場所に格納して簡単に実行できないため、これは私にとって最も厄介なビットです。
Michael Scott Cuthbert

14
この回答は現在、__name__およびに関するいくつかの重要な詳細についてはオフになっていsys.pathます。具体的にはpython -m pkg.mod__name____main__、ではなくに設定されpkg.modます。相対インポートは、この場合__package__ではなくを使用して解決され__name__ます。また、Pythonはsys.path実行時に現在のディレクトリではなくスクリプトのディレクトリを追加しますpython path/to/script.pysys.pathを含む他のほとんどの方法を実行すると、現在のディレクトリが追加されますpython -m pkg.mod
user2357112は18:22にMonica

42

これは本当にpython内の問題です。混乱の原因は、人々が相対インポートを誤って相対パスと見なしていることです。

たとえば、faa.pyに次のように記述したとします。

from .. import foo

これは、パッケージの一部として、実行中にfaa.pyがpythonによって識別およびロードされた場合にのみ意味があります。その場合、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

6
正しい解決策は from __future__ import absolute_import、ユーザーにコードを正しく使用することを強制することです。これにより、いつでも実行できますfrom . import foo
Giacomo Alzetta

@Giacomo:私の問題に対する完全に正しい答え。ありがとう!
ファビオ

8

以下は、例として適合するように変更された一般的なレシピです。パッケージとして作成されたPythonライブラリを処理するために現在使用しています。相互依存ファイルを含み、それらの一部を少しずつテストできるようにしたいと考えています。これlib.fooを呼び出してlib.fileA、関数f1f2、および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で同じように機能することに注意してください):

  1. として実行する場合 import libfrom lib import foo通常のコードからインポートまたは通常のパッケージインポートとして、__packageis libおよび__name__is lib.fooです。からのインポート.fileAなど、最初のコードパスを使用します。

  2. として実行する場合python lib/foo.py__package__Noneとに__name__なります__main__

    2番目のコードパスを使用します。libディレクトリはすでにになりsys.path、それを追加する必要はありませんので。fileA等から輸入しております。

  3. libとしてディレクトリ内で実行した場合python foo.pyの動作は、ケース2の場合と同じです。

  4. 内で実行する場合 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回はパッケージを介してインポートされ、その後再び__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を参照してください。)Nick Coghlan氏は次のように述べています。

この次のトラップは、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、インポートを実行するのに十分な時間を変更してから、元の状態に戻します(_iifのコピーを1つ追加した場合に限り、ifのコピーを1つ削除します_i)。


7

他の多くの人と一緒にこれについて熟考した後、この記事Dorian 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
それは実際にそれを解決します。しかし、それは本当に厄介です。なぜこれがデフォルトの動作ではないのですか?
lo tolmencre

4

以下は私がお勧めしない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()

2

同様の問題があり、Pythonモジュールの検索パスを変更したくなく、スクリプトから比較的モジュールをロードする必要がありました( BrenBarnが上でうまく説明したように、「スクリプトはすべてに対して相対的にインポートできない」にもかかわらず)。

そこで、次のハックを使用しました。残念ながら、それはimpバージョン3.4以降廃止予定となったモジュールに依存しており、その代わりに削除されましたimportlib。(これもで可能importlibですか?わかりません。)それでも、今のところハックは機能しています。

フォルダにあるスクリプトからmoduleXinのメンバーにアクセスする例:subpackage1subpackage2

#!/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 *

それは良く見えます...残念ですが、それでも親ディレクトリの名前をファイルに埋め込む必要があります...多分それはimportlibで改善できます。たぶんimportlibは、単純なユースケースでは相対的なインポートを「そのまま動作させる」ためにモンキーパッチを適用することさえできます。ひび割れます。
Andrew Wagner

私はpython 2.7.14を使っています。このようなものはまだ機能しますか?
user3474042 2018

私はpython 2.7.10で両方のアプローチをテストしましたが、それらは私にとってはうまくいきました。実際のところ、2.7で非推奨のimpモジュールの問題はないので、なお良いでしょう。
Lars

2

__name__ 問題のコードがグローバル名前空間で実行されるか、インポートされたモジュールの一部として実行されるかに応じて変化します。

コードがグローバルスペースで実行されていない場合__name__は、モジュールの名前になります。それがグローバル名前空間で実行されている場合-たとえば、コンソールに入力するか、モジュールをスクリプトとして実行すると、python.exe yourscriptnamehere.pyはに__name__なり"__main__"ます。

多くのPythonコードを if __name__ == '__main__'使用して、コードがグローバル名前空間から実行されているかどうかをテストしていることを確認します。これにより、スクリプトとしても機能するモジュールを使用できます。

コンソールからこれらのインポートを実行しようとしましたか?


ああ、あなたは-mに言及します。これにより、モジュールがスクリプトとして実行されます。if__name__ == '__main__'をそこに貼り付けた場合、-mによって '__main__'であることがわかります。それはあなたが相対的なインポートを実行できるようにする必要があり、トップレベル...ではありませんので、ちょうど別のモジュールにあなたのモジュールをインポートしてみてください
theodox

これらのインポートをコンソールから実行しようとしましたが、アクティブなファイルが正しいモジュールです。

@Stopforgettingmyaccounts ...:「アクティブファイル」とはどういう意味ですか?
BrenBarn 2013年

私はPyscripterを使用しています。これらのインポートを実行したとき、私はmoduleX.pyにいました:from .moduleY import spam および from。ModuleYをインポートします。

.moduleYに続いてmoduleY.spam()をインポートしませんか?
セオドックス

2

@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になり、相対インポートが見つかります


あなたがこれについて私を案内してくれることを願っています。次のリンクで、ケース3に進むと、ソリューション1は不可能であることが示されています。これを確認して教えてください。それは私に非常に役立ちます。chrisyeh96.github.io/2017/08/08/…–
変数

@variableリンクにタイプミスがあり、編集は許可されていません。ケース3を確認しましたが、現在の状況に正確には従っていません。私がpython 2でその例を試したとき、何かを逃したと思うような問題はありませんでした。新しい質問を投稿する必要があるかもしれませんが、より明確な例を提供する必要があります。ケース4では、ここでの私の回答について触れています。インタプリタが親ディレクトリで開始しない限り、相対インポート用のディレクトリに移動できません
Brad Dre

おかげで私は、Python 3を参照すると、ここで質問していstackoverflow.com/questions/58577767/...
変数

1

相対インポートは、モジュールの名前属性を使用して、パッケージ階層におけるそのモジュールの位置を決定します。モジュールの名前にパッケージ情報が含まれていない場合(「メイン」に設定されているなど)、相対インポートは、モジュールが実際にファイルシステムのどこに配置されているかに関係なく、モジュールが最上位モジュールであるかのように解決されます。

この質問の視聴者に役立つかもしれないPyPiに小さなpythonパッケージを書いてください。インポートファイルのディレクトリに直接移動せずに、パッケージ/プロジェクト内から上位レベルのパッケージを含むインポートを含むpythonファイルを実行できるようにする場合、パッケージは回避策として機能します。https://pypi.org/project/import-anywhere/


-2

Pythonが「非パッケージでの相対インポートを試みました」に戻らないようにするため。パッケージ/

init .py subpackage1 / init .py moduleX.py moduleY.py subpackage2 / init .py moduleZ.py moduleA.py

このエラーは、親ファイルに相対インポートを適用している場合にのみ発生します。たとえば、moduleA.pyで「print(name)」をコーディングした後、親ファイルはすでにmainを返します。したがって、このファイルはすでに mainですそれ以上親パッケージを返すことはできません。相対インポートは、パッケージsubpackage1およびsubpackage2のファイルで必要です。「..」を使用して、親ディレクトリまたはモジュールを参照できます。ただし、親は、すでに最上位のパッケージの場合、その親ディレクトリ(パッケージ)を超えることはできません。親に相対インポートを適用しているそのようなファイルは、絶対インポートのアプリケーションでのみ機能します。親パッケージで絶対インポートを使用する場合、プロジェクトのトップレベルを定義するPYTHON PATHの概念により、ファイルがサブパッケージにある場合でも、Pythonが誰がパッケージのトップレベルであるかを認識しているため、エラーは発生しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.