简体   繁体   English

Python子模块导入疯狂

[英]Python Submodule Importing Madness

I'm banging my head against the wall with some basic Python importing. 我通过一些基本的Python导入使我的头撞到了墙上。 I have simplified the problem as much as possible hoping I'd be able to expand this to a larger scale if I understand how this works 我已尽可能简化了该问题,希望如果我了解其工作原理,便可以将其扩展到更大的规模

Here is the dilemma - 这是两难的境地 -
run.py from inside the submodule p1 works, but NOT when it's at the top level. 子模块p1内部的run.py可以工作,但是在顶层时则不能。 Why? 为什么?

(version Python 3.6.3) (版本Python 3.6.3)


Structure: 结构体:

/sandbox
    __init__.py
    /p1
        __init__.py
        file1.py
        run.py
    run.py

/sandbox/p1/__init__.py /sandbox/p1/__init__.py

__all__ = ["file1", "file2"]

/sandbox/p1/file1.py /sandbox/p1/file1.py

from file2 import B
class A(object):
    pass

/sandbox/p1/file2.py /sandbox/p1/file2.py

class B(object):
    pass

/sandbox/p1/run.py /sandbox/p1/run.py

from file1 import A
a = A()

/sandbox/run.py /sandbox/run.py

from p1 import file1
a = file1.A()

Doing: 这样做:

python p1/run.py (works fine) python p1/run.py (工作正常)
python run.py

Traceback (most recent call last): File "run.py", line 2, in from p1 import file1 File ".../sandbox/p1/file1.py", line 1, in from file2 import B ModuleNotFoundError: No module named 'file2' 追溯(最近一次通话):文件“ run.py”,第2行,来自p1导入file1文件“ ... / sandbox / p1 / file1.py”,第1行,来自file2导入B ModuleNotFoundError:无模块名为“ file2”

(I) no module named 'file2' (I)没有名为'file2'的模块

You encountered No module named 'file2' because you run run.py outside a package, when file1 import file2 , python cannot find file2 as the module directory not in module search path. No module named 'file2'遇到No module named 'file2'因为您在run.py外部运行run.py ,当file1导入file2 ,python找不到file2作为不在模块搜索路径中的模块目录。

For your scenario, file1 & file2 are 2 modules which in the same package, for this situation, suggest you use relative import , this is the best practice. 对于您的情况, file1file2是2个模块,它们在同一软件包中,对于这种情况,建议您使用relative import ,这是最佳实践。

file1.py file1.py

from .file2 import B
class A(object):
    pass

Then, python run.py works. 然后, python run.py工作。

(II) attempted relative import with no known parent package (II)在没有已知父包的情况下尝试相对导入

As you mentioned you will see next if execute python p1/run.py : 如您所述,如果执行python p1/run.py您将看到下一个:

attempted relative import with no known parent package 尝试相对导入,但没有已知的父程序包

What does it mean? 这是什么意思?

This because relative import can just be supported in the module which in package. 这是因为relative import只能在包中的模块中受支持。

You may say file1.py is in package p1 , why still see the error? 您可能会说file1.py在软件包p1 ,为什么仍然看到错误?

This is because python use __name__ to determine if this module in package or not, not by the position of it. 这是因为python使用__name__来确定此模块是否在包中,而不是通过其位置来确定。

Change file1.py as follows: 如下更改file1.py

print(__name__)
from .file2 import B
class A(object):
    pass

Next is the output: 接下来是输出:

python run.py python run.py

p1.file1 p1.file1

python p1/run.py python p1 / run.py

file1 文件1

For python p1/run.py , because it runs in the package, python will fail to know it is in a package, so output is file1 . 对于python p1/run.py ,因为它在软件包中运行,所以python将无法知道它在软件包中,因此输出为file1

If __name__ does not has . 如果__name__没有. , python will think it's not in package, so relative import failure. ,python会认为它不在软件包中,因此相对导入失败。

(III) Finally, what if you really want to execute python p1/run.py , eg unittest your package? (III)最后,如果您真的要执行python p1/run.py ,例如,对程序包进行单元测试,该怎么办?

Use python -m p1.run , this should works to execute top script which inside a package. 使用python -m p1.run ,这应该可以执行包中的顶级脚本。

Python makes it intentionally difficult to mix scripts in a modules. Python使得故意在模块中混合脚本变得困难。 The way this can be handled is like this: 可以这样处理:

/project
    /scripts
        run.py
    /sandbox
        __init__.py
        /p1
            __init__.py
            file1.py
            file2.py

/project/sandbox/p1/file1.py /project/sandbox/p1/file1.py

from .file2 import B
class A(object):
    pass

/project/sandbox/p1/file2.py /project/sandbox/p1/file2.py

class B(object):
    pass

/project/scripts/run.py /project/scripts/run.py

from sandbox.p1.file1 import A
a = A()

I make sure that the path to /project is in a .pth file in the site-packages of the virtual environment I want to use it from. 我确保/project的路径位于我要在其中使用的虚拟环境的站点包中的.pth文件中。

conda 康达

If you use conda, you can use conda develop 如果使用conda,则可以使用conda develop

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM