1242

我想从同一目录中的另一个文件导入一个函数。

有时它对我有用,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

我不明白这里的逻辑,我找不到任何解释。这看起来完全随机。

有人可以向我解释这一切背后的逻辑是什么吗?

4

24 回答 24

943

不幸的是,这个模块需要在包中,有时它还需要作为脚本运行。知道我怎么能做到这一点吗?

有这样的布局很常见......

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 __name__ == '__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 __name__ == '__main__':
    _test()

……还有main.py这样的……

#!/usr/bin/env python3

from mypackage.myothermodule import add

def main():
    print(add('1', '1'))

if __name__ == '__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先用这个来敲击 in 代码...

import sys
import os

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(SCRIPT_DIR))

from mypackage.mymodule import as_int

这有点痛苦,但在某位 Guido van Rossum 写的电子邮件中,有一个线索可以解释为什么......

我对此以及任何其他提议的__main__ 机器玩弄都是-1。唯一的用例似乎是运行恰好位于模块目录中的脚本,我一直将其视为反模式。要让我改变主意,你必须说服我它不是。

在包中运行脚本是否是反模式是主观的,但我个人发现它在我拥有的包含一些自定义 wxPython 小部件的包中非常有用,因此我可以为任何源文件运行脚本以显示wx.Frame仅包含该小部件用于测试目的。

于 2013-06-07T13:14:23.540 回答
478

解释

PEP 328

相对导入使用模块的 __name__ 属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它被设置为'__main__') ,那么无论模块实际位于文件系统上的什么位置,相对导入都会像模块一样被解析为顶级模块。

在某些时候PEP 338PEP 328冲突:

...相对导入依赖__name__来确定当前模块在包层次结构中的位置。在主模块中,__name__的值始终为'__main__',因此显式相对导入将始终失败(因为它们仅适用于包内的模块)

为了解决这个问题,PEP 366引入了顶级变量__package__

通过添加新的模块级别属性,如果使用-m 开关执行模块,此 PEP 允许相对导入自动工作。当文件按名称执行时,模块本身的少量样板将允许相对导入工作。[...]当 [属性] 存在时,相对导入将基于此属性而不是模块__name__属性。[...] 当主模块由其文件名指定时,__package__属性将设置为None。[...]当导入系统在没有设置 __package__ (或设置为 None )的模块中遇到显式相对导入时,它将计算并存储正确的值__name__.rpartition('.')[0] 用于普通模块__name__用于包初始化模块)

(强调我的)

如果__name__'__main__',则__name__.rpartition('.')[0]返回空字符串。这就是错误描述中有空字符串文字的原因:

SystemError: Parent module '' not loaded, cannot perform relative import

PyImport_ImportModuleLevelObjectCPython函数的相关部分:

if (PyDict_GetItem(interp->modules, package) == NULL) {
    PyErr_Format(PyExc_SystemError,
            "Parent module %R not loaded, cannot perform relative "
            "import", package);
    goto error;
}

如果 CPython 无法在(accessible as ) 中找到package(包的名称),则会引发此异常。由于是“将模块名称映射到已经加载的模块的字典”,现在很明显父模块必须在执行相对导入之前显式地绝对导入interp->modulessys.modulessys.modules

注意: issue 18018 的补丁添加了另一个ifblock,它将上面的代码之前执行:

if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
    PyErr_SetString(PyExc_ImportError,
            "attempted relative import with no known parent package");
    goto error;
} /* else if (PyDict_GetItem(interp->modules, package) == NULL) {
    ...
*/

如果package(同上)为空字符串,错误信息为

ImportError: attempted relative import with no known parent package

但是,您只会在 Python 3.6 或更高版本中看到这一点。

解决方案 #1:使用 -m 运行脚本

考虑一个目录(这是一个 Python):

.
├── package
│   ├── __init__.py
│   ├── module.py
│   └── standalone.py

中的所有文件都以相同的 2 行代码开头:

from pathlib import Path
print('Running' if __name__ == '__main__' else 'Importing', Path(__file__).resolve())

我将这两行包括在内只是为了使操作顺序变得明显。我们可以完全忽略它们,因为它们不会影响执行。

__init__.pymodule.py仅包含这两行(即,它们实际上是空的)。

Standalone.py还尝试通过相对导入来导入module.py :

from . import module  # explicit relative import

我们很清楚这/path/to/python/interpreter package/standalone.py将失败。但是,我们可以使用-m命令行选项运行模块,该选项将“搜索sys.path命名模块并将其内容作为__main__模块执行”

vaultah@base:~$ python3 -i -m package.standalone
Importing /home/vaultah/package/__init__.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/module.py
>>> __file__
'/home/vaultah/package/standalone.py'
>>> __package__
'package'
>>> # The __package__ has been correctly set and module.py has been imported.
... # What's inside sys.modules?
... import sys
>>> sys.modules['__main__']
<module 'package.standalone' from '/home/vaultah/package/standalone.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>

-m为您完成所有导入的工作并自动设置__package__,但您可以在

解决方案 #2:手动设置 __package__

请将其视为概念证明而不是实际解决方案。它不适合在实际代码中使用。

PEP 366有解决此问题的方法,但是,它不完整,因为__package__单独设置是不够的。您将需要在模块层次结构中导入至少N个前面的包,其中N是将搜索正在导入的模块的父目录的数量(相对于脚本的目录)。

因此,

  1. 将当前模块的第 N 个前驱的父目录添加到sys.path

  2. 删除当前文件的目录sys.path

  3. 使用其完全限定名称导入当前模块的父模块

  4. 设置__package__为从2开始的完全限定名称

  5. 执行相对导入

我将从解决方案 #1中借用文件并添加更多子包:

package
├── __init__.py
├── module.py
└── subpackage
    ├── __init__.py
    └── subsubpackage
        ├── __init__.py
        └── standalone.py

这次standalone.py将使用以下相对导入从包包中导入module.py

from ... import module  # N = 3

我们需要在该行之前加上样板代码,以使其工作。

import sys
from pathlib import Path

if __name__ == '__main__' and __package__ is None:
    file = Path(__file__).resolve()
    parent, top = file.parent, file.parents[3]

    sys.path.append(str(top))
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass

    import package.subpackage.subsubpackage
    __package__ = 'package.subpackage.subsubpackage'

from ... import module # N = 3

它允许我们通过文件名执行standalone.py

vaultah@base:~$ python3 package/subpackage/subsubpackage/standalone.py
Running /home/vaultah/package/subpackage/subsubpackage/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/subpackage/__init__.py
Importing /home/vaultah/package/subpackage/subsubpackage/__init__.py
Importing /home/vaultah/package/module.py

可以在此处找到包含在函数中的更通用的解决方案。示例用法:

if __name__ == '__main__' and __package__ is None:
    import_parents(level=3) # N = 3

from ... import module
from ...module.submodule import thing

解决方案 #3:使用绝对导入和setuptools

步骤是 -

  1. 用等效的绝对导入替换显式相对导入

  2. 安装package以使其可导入

例如,目录结构可能如下

.
├── project
│   ├── package
│   │   ├── __init__.py
│   │   ├── module.py
│   │   └── standalone.py
│   └── setup.py

setup.py在哪里

from setuptools import setup, find_packages
setup(
    name = 'your_package_name',
    packages = find_packages(),
)

其余文件是从解决方案 #1中借来的。

安装将允许您导入包,而不管您的工作目录如何(假设不会有命名问题)。

我们可以修改standalone.py来利用这个优势(步骤1):

from package import module  # absolute import

将您的工作目录更改为project并运行/path/to/python/interpreter setup.py install --user--user将包安装在您的站点包目录中)(步骤 2):

vaultah@base:~$ cd project
vaultah@base:~/project$ python3 setup.py install --user

让我们验证现在可以将standalone.py作为脚本运行:

vaultah@base:~/project$ python3 -i package/standalone.py
Running /home/vaultah/project/package/standalone.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>

注意:如果你决定走这条路,你最好使用虚拟环境来单独安装包。

解决方案#4:使用绝对导入和一些样板代码

坦率地说,安装不是必需的 - 您可以在脚本中添加一些样板代码以使绝对导入工作。

我将从解决方案 #1中借用文件并更改Standalone.py

  1. 在尝试使用绝对导入从包中导入任何内容之前,将的父目录添加到:sys.path

    import sys
    from pathlib import Path # if you haven't already done so
    file = Path(__file__).resolve()
    parent, root = file.parent, file.parents[1]
    sys.path.append(str(root))
    
    # Additionally remove the current file's directory from sys.path
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass
    
  2. 将相对导入替换为绝对导入:

    from package import module  # absolute import
    

Standalone.py运行没有问题:

vaultah@base:~$ python3 -i package/standalone.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>

我觉得我应该警告你:尽量不要这样做,特别是如果你的项目结构复杂。


作为旁注,PEP 8建议使用绝对导入,但指出在某些情况下显式相对导入是可以接受的:

建议使用绝对导入,因为它们通常更具可读性并且往往表现更好(或至少提供更好的错误消息)。[...] 但是,显式相对导入是绝对导入的可接受替代方案,特别是在处理复杂的包布局时,使用绝对导入会不必要地冗长。

于 2015-01-26T16:54:06.947 回答
200

把它放在你包的 __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。

于 2018-03-20T03:07:34.190 回答
59

我遇到了这个问题。hack 解决方法是通过 if/else 块导入,如下所示:

#!/usr/bin/env python3
#myothermodule

if __name__ == '__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 __name__ == '__main__':
    _test()
于 2015-01-26T14:21:36.923 回答
28

SystemError:父模块''未加载,无法执行相对导入

这意味着您正在将包内的模块作为脚本运行。在包中混合脚本很棘手,应尽可能避免。使用导入包并运行您的scripty函数的包装脚本。

如果您的顶级目录被称为foo,它位于您的PYTHONPATH模块搜索路径中,并且您在bar那里有一个包(它是您希望有一个__init__.py文件的目录),则脚本不应该放在里面bar,而应该foo 放在最好的。

请注意,脚本与此处的模块不同,因为它们被用作python命令的文件名参数,通过使用python <filename>或通过#!(shebang) 行。它直接作为__main__模块加载(这就是为什么if __name__ == "__main__":在脚本中工作的原因),并且没有包上下文可以构建相对导入。

您的选择

  • 如果可以,使用setuptools(或poetryflit,这有助于简化打包)打包您的项目,并创建控制台脚本入口点;安装你的项目pip然后创建知道如何正确导入你的包的脚本。你可以使用 本地安装你的包pip install -e .,所以它仍然可以就地编辑。

  • 否则,永远,永远,使用python path/to/packagename/file.py,总是使用python path/to/script.pyscript.py可以使用from packagename import ...

  • 作为后备方案,您可以使用-m命令行开关来告诉 Python 导入模块并将其用作__main__文件。但是,这不适用于 shebang 行,因为不再有脚本文件。

    如果您使用python -m foo.barfoo/bar.pysys.path目录中找到,则将其导入并__main__使用正确的包上下文执行。如果bar也是一个包,在里面foo/,它必须有一个__main__.py文件(foo/bar/__main__.py比如目录的路径sys.path)。

  • 在极端情况下,通过直接设置添加 Python 用来解析相对导入的元数据__package__;文件foo/bar/spam.py,可导入为foo.bar.spam,被赋予全局__package__ = "foo.bar". 它只是Python 在导入时设置的另一个全局变量,例如__file__and 。__name__

sys.path

以上都要求您的包可以被导入,这意味着它需要在sys.path. 这里也有几个选项:

  • 找到的目录path/to/script.py(so path/to) 会自动添加到sys.path. 执行python path/to/foo.py添加path/tosys.path.

  • 如果您打包了项目(使用setuptoolspoetryflit其他 Python 打包工具)并安装了它,则该包已添加到正确的位置。

  • 作为最后的手段,为sys.path自己添加正确的目录。如果包可以相对于脚本文件定位,则使用__file__脚本全局命名空间中的变量(例如,使用pathlib.PathobjectHERE = Path(__file__).resolve().parent是对文件所在目录的引用,作为绝对路径)。

于 2021-09-08T11:25:49.793 回答
19

对于 PyCharm 用户:

我也得到了,ImportError: attempted relative import with no known parent package因为我添加了.符号来消除 PyCharm 解析错误。PyCharm 错误地报告无法找到:

lib.thing import function

如果您将其更改为:

.lib.thing import function

它使错误静音,但随后您会得到上述ImportError: attempted relative import with no known parent package. 只需忽略 PyCharm 的解析器。这是错误的,尽管它说了什么,但代码运行良好。

于 2020-07-29T20:21:50.380 回答
12

为了避免这个问题,我设计了一个使用repackage包的解决方案,它已经为我工作了一段时间。它将上层目录添加到 lib 路径:

import repackage
repackage.up()
from mypackage.mymodule import myfunction

Repackage 可以使用智能策略(检查调用堆栈)进行适用于各种情况的相对导入。

于 2017-12-06T09:26:59.700 回答
11

希望这对那里的人有价值 - 我浏览了六篇 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,请尝试以下任一方法:

  1. 运行您的代码并显式包含路径,如下所示: $ PYTHONPATH=. python3 test/my_module/module_test.py
  2. 为避免调用PYTHONPATH=.,请创建一个setup.py包含如下内容的文件并运行python setup.py development以将包添加到路径:
# setup.py
from setuptools import setup, find_packages

setup(
    name='sample',
    packages=find_packages()
)
于 2018-04-17T19:40:32.547 回答
8

我需要从主项目目录运行 python3 以使其工作。

例如,如果项目具有以下结构:

project_demo/
├── main.py
├── some_package/
│   ├── __init__.py
│   └── project_configs.py
└── test/
    └── test_project_configs.py

解决方案

我会在文件夹project_demo/中运行 python3 ,然后执行

from some_package import project_configs
于 2018-09-11T18:49:29.027 回答
6

我收到了这个ImportError:尝试使用没有已知父包的相对导入

在我的程序中,我使用当前路径中的文件来导入其功能。

from .filename import function

然后我用包名修改了当前路径(点) 。这解决了我的问题。

from package_name.filename import function

希望以上回答对你有所帮助。

于 2020-06-14T07:39:03.680 回答
6

我尝试了以上所有方法都无济于事,只是意识到我错误地-在我的包名中有一个。

简而言之,没有-在目录中__init__.py是哪里。在发现这种愚蠢之后,我从未感到高兴。

于 2020-12-18T03:36:24.273 回答
6

我的样板文件是在可运行的独立文件module中使用相对导入来制作的。package

package/module.py

## Standalone boilerplate before relative imports
if __package__ is None:                  
    DIR = Path(__file__).resolve().parent
    sys.path.insert(0, str(DIR.parent))
    __package__ = DIR.name

from . import variable_in__init__py
from . import other_module_in_package
...

现在您可以以任何方式使用您的模块:

  1. 像往常一样运行模块:python -m package.module
  2. 将其用作模块:python -c 'from package import module'
  3. 独立运行:python package/module.py
  4. 或使用 shebang ( #!/bin/env python) :package/module.py

注意!如果sys.path.append您的sys.path.insert名称module与您的package. 例如my_script/my_script.py

当然,如果您有来自包层次结构中更高级别的相对导入,这还不够,但在大多数情况下,这还好。

于 2021-01-18T19:05:24.603 回答
6

TL;DR:对@Aya 的回答,使用pathlib库进行了更新,并适用于未定义的 Jupyter 笔记本__file__

您要根据 编写代码的位置my_function定义导入。../my_Folder_where_the_package_lives/my_package.py

然后做:

import os
import sys
import pathlib

PACKAGE_PARENT = pathlib.Path(__file__).parent
#PACKAGE_PARENT = pathlib.Path.cwd().parent # if on jupyter notebook
SCRIPT_DIR = PACKAGE_PARENT / "my_Folder_where_the_package_lives"
sys.path.append(str(SCRIPT_DIR))

from my_package import my_function
于 2021-08-10T17:09:02.243 回答
6

从同一目录导入

首先,您可以从同一目录导入。

这是文件结构...

Folder
 |
 ├─ Scripts
 |   ├─ module123.py
 |
 ├─ main.py
 ├─ script123.py

这是main.py

from . import script123
from Scripts import module123

如您所见,.从当前目录的导入中导入。

注意:如果使用除 IDLE 以外的任何方式运行,请确保main.py在运行之前将您的终端导航到与文件相同的目录。

此外,从本地文件夹导入也可以。

从父目录导入

正如我的 GitHub gist here中所见,有以下方法。

采取以下文件树...

ParentDirectory
 ├─ Folder
 |   |
 |   ├─ Scripts
 |   |   ├─ module123.py
 |   |
 |   ├─ main.py
 |   ├─ script123.py
 |
 ├─ parentModule.py

然后,只需将此代码添加到main.py文件顶部即可。

import inspect
import os
import sys

current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parent_dir = os.path.dirname(current_dir)
sys.path.insert(0, parent_dir)

from ParentDirectory import Stuff
于 2021-09-20T17:34:43.627 回答
4

如果两个包都在您的导入路径 (sys.path) 中,并且您想要的模块/类在 example/example.py 中,那么在没有相对导入的情况下访问该类尝试:

from example.example import fkt
于 2017-03-09T22:18:30.637 回答
3

如果上述方法都不适合您,您可以明确指定模块。

目录:

├── Project
│     ├── Dir
│     │    ├── __init__.py
│     │    ├── module.py
│     │    └── standalone.py

解决方案:

#in standalone.py
from Project.Dir.module import ...

module - 要导入的模块

于 2020-10-05T16:34:38.630 回答
2

我认为最好的解决方案是为您的模块创建一个包: 以下是有关如何执行此操作的更多信息。

一旦你有了一个包,你就不需要担心相对导入,你可以做绝对导入。

于 2019-10-17T09:16:38.030 回答
2

我在使用 Django 时经常遇到这种情况,因为很多功能都是从manage.py脚本执行的,但我也希望我的一些模块也可以直接作为脚本运行(理想情况下,你可以让它们成为manage.py指令,但我们不是还没有)。

这是这样一个项目的模型;

├── dj_app
│   ├── models.py
│   ├── ops
│   │   ├── bar.py
│   │   └── foo.py
│   ├── script.py
│   ├── tests.py
│   ├── utils.py
│   └── views.py
└── manage.py

这里的重要部分是manage.py,dj_app/script.pydj_app/tests.py。我们还有子模块dj_app/ops/bar.pydj_app/ops/foo.py其中包含我们想要在整个项目中使用的更多项目。

问题的根源通常来自希望您的脚本方法具有在您运行时调用dj_app/script.py的测试用例。dj_app/tests.pymanage.py test

这就是我设置项目及其imports 的方式;

# dj_app/ops/foo.py
# Foo operation methods and classes
foo_val = "foo123"

.

# dj_app/ops/bar.py
# Bar operations methods and classes
bar_val = "bar123"

.

# dj_app/script.py
# script to run app methods from CLI

# if run directly from command line
if __name__ == '__main__':
    from ops.bar import bar_val
    from ops.foo import foo_val

# otherwise
else:
    from .ops.bar import bar_val
    from .ops.foo import foo_val

def script_method1():
    print("this is script_method1")
    print("bar_val: {}".format(bar_val))
    print("foo_val: {}".format(foo_val))


if __name__ == '__main__':
    print("running from the script")
    script_method1()

.

# dj_app/tests.py
# test cases for the app
# do not run this directly from CLI or the imports will break
from .script import script_method1
from .ops.bar import bar_val
from .ops.foo import foo_val 

def main():
    print("Running the test case")
    print("testing script method")
    script_method1()

if __name__ == '__main__':
    print("running tests from command line")
    main()

.

# manage.py
# just run the test cases for this example
import dj_app.tests
dj_app.tests.main()

.

运行测试用例manage.py

$ python3 manage.py
Running the test case
testing script method
this is script_method1
bar_val: bar123
foo_val: foo123

自行运行脚本;

$ python3 dj_app/script.py
running from the script
this is script_method1
bar_val: bar123
foo_val: foo123

请注意,如果您尝试test.py直接运行,则会出现错误,所以不要这样做;

$ python3 dj_app/tests.py
Traceback (most recent call last):
  File "dj_app/tests.py", line 5, in <module>
    from .script import script_method1
ModuleNotFoundError: No module named '__main__.script'; '__main__' is not a package

如果我遇到更复杂的导入情况,我通常最终会实现这样的东西来破解它;

import os
import sys
THIS_DIR = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, THIS_DIR)
from script import script_method1
sys.path.pop(0)
于 2021-06-30T13:44:08.630 回答
1

这是我的项目结构

├── folder
|   | 
│   ├── moduleA.py
|   |   |
|   |   └--function1()
|   |       └~~ uses function2()
|   | 
│   └── moduleB.py
|       | 
|       └--function2()
|   
└── main.py
     └~~ uses function1()

这是我的moduleA进口moduleBmain进口moduleA

我添加了下面的代码片段moduleA以导入moduleB

try:
    from .moduleB import function2 
except:
    from moduleB import function2 

现在我既可以执行main.py也可以moduleA.py单独执行

这是一个解决方案吗?

于 2021-07-09T06:56:15.820 回答
1

以下解决方案在Python3上进行了测试

├── classes
|   |
|   ├──__init__.py
|   | 
│   ├── userclass.py
|   |   |
|   |   └--viewDetails()
|   |       
|   | 
│   └── groupclass.py
|       | 
|       └--viewGroupDetails()
|   
└── start.py
     └~~ uses function1()

现在,为了使用 userclass 的 viewDetails 或 groupclass 的 viewGroupDetails,首先在 classess 目录的_init _.py 中定义。

例如:在_init _.py

from .userclasss import viewDetails

from .groupclass import viewGroupDetails

Step2:现在,在start.py中我们可以直接导入viewDetails

例如:在 start.py

from classes import viewDetails
from classes import viewGroupDetails
于 2022-01-07T05:24:19.507 回答
0

我有一个类似的问题:我需要一个使用通用常量来配合的 Linux 服务和 cgi 插件。这样做的“自然”方法是将它们放在包的init .py 中,但我无法使用 -m 参数启动 cgi 插件。

我的最终解决方案类似于上面的解决方案 #2:

import sys
import pathlib as p
import importlib

pp = p.Path(sys.argv[0])
pack = pp.resolve().parent

pkg = importlib.import_module('__init__', package=str(pack))

缺点是必须在常量(或常用函数)前加上 pkg:

print(pkg.Glob)
于 2020-04-06T07:55:47.180 回答
0

将要从中导入的文件移动到外部目录会有所帮助。
当您的主文件在其自己的目录中创建任何其他文件时,这非常有用。
例如:
之前:
项目
|---dir1
|-------main.py
|-------module1.py
之后:
项目
|---module1.py
|---dir1
|-- -----main.py

于 2020-09-01T17:09:10.613 回答
0

TLDR;通过在 python 脚本的入口点添加以下内容,将脚本路径附加到系统路径

import os.path
import sys
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)))

现在就是这样,您可以在 PyCharma 以及终端中运行您的项目!

于 2020-11-05T10:32:01.650 回答
-3

我有一个类似的问题,并通过在工作目录中创建一个指向包的符号链接来解决它:

ln -s ../../../my_package my_package

然后像往常一样导入它:

import my_package

我知道这更像是“Linux”解决方案而不是“Python”解决方案。但它仍然是一种有效的方法。

于 2021-01-08T08:07:25.777 回答