Joh*_*nal 589 python python-import python-3.x
我想从同一目录中的另一个文件导入一个函数.
有时它适用于我,from .mymodule import myfunction
但有时我会得到:
SystemError: Parent module '' not loaded, cannot perform relative import
Run Code Online (Sandbox Code Playgroud)
有时它适用from mymodule import myfunction
,但有时我也得到:
SystemError: Parent module '' not loaded, cannot perform relative import
Run Code Online (Sandbox Code Playgroud)
我不明白这里的逻辑,我找不到任何解释.这看起来完全随机.
有人可以向我解释这一切背后的逻辑是什么吗?
Aya*_*Aya 455
不幸的是,这个模块需要在包内,并且它有时也需要作为脚本运行.知道如何实现这一目标吗?
这样的布局很常见......
main.py
mypackage/
__init__.py
mymodule.py
myothermodule.py
Run Code Online (Sandbox Code Playgroud)
......有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()
Run Code Online (Sandbox Code Playgroud)
...... 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()
Run Code Online (Sandbox Code Playgroud)
......和main.py
这样......
#!/usr/bin/env python3
from mypackage.myothermodule import add
def main():
print(add('1', '1'))
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
...当你运行的正常工作main.py
或mypackage/mymodule.py
,但失败mypackage/myothermodule.py
,由于相对进口...
from .mymodule import as_int
Run Code Online (Sandbox Code Playgroud)
你应该运行它的方式是......
python3 -m mypackage.myothermodule
Run Code Online (Sandbox Code Playgroud)
...但它有点冗长,并且与像shebang这样的线条混合不好#!/usr/bin/env python3
.
对于这种情况最简单的修复,假设名称mymodule
是全局唯一的,将避免使用相对导入,只需使用...
from mymodule import as_int
Run Code Online (Sandbox Code Playgroud)
...虽然,如果它不是唯一的,或者你的包结构更复杂,你需要包含包含你的包目录的目录PYTHONPATH
,并像这样做......
from mypackage.mymodule import as_int
Run Code Online (Sandbox Code Playgroud)
...或者如果你想让它"开箱即用",你可以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
Run Code Online (Sandbox Code Playgroud)
这有点痛苦,但有一个线索,为什么在某个Guido van Rossum写的电子邮件中 ......
我在这个以及任何其他提议的
__main__
机械装置上都是-1 .唯一的用例似乎是运行脚本,这些脚本恰好位于模块的目录中,我一直将其视为反模式.为了让我改变主意,你必须让我相信它不是.
在包内运行脚本是否是反模式是主观的,但我个人认为它在包含一些自定义wxPython小部件的包中非常有用,所以我可以运行任何源文件的脚本来显示wx.Frame
仅包含用于测试目的的小部件.
vau*_*tah 220
来自PEP 328
相对导入使用模块的__name__属性来确定模块在包层次结构中的位置.如果模块的名称不包含任何包信息(例如,它设置为'__main__'), 则解析相对导入,就像模块是顶级模块一样,无论模块实际位于文件系统的哪个位置.
...相对导入依赖于__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
Run Code Online (Sandbox Code Playgroud)
CPython PyImport_ImportModuleLevelObject
功能的相关部分:
if (PyDict_GetItem(interp->modules, package) == NULL) {
PyErr_Format(PyExc_SystemError,
"Parent module %R not loaded, cannot perform relative "
"import", package);
goto error;
}
Run Code Online (Sandbox Code Playgroud)
如果CPython无法package
在interp->modules
(可访问的)中找到(包的名称),则会引发此异常sys.modules
.由于sys.modules
是"将模块名称映射到已经加载的模块的字典",现在很清楚在执行相对导入之前必须显式绝对导入父模块.
注意:问题18018中 的补丁添加了另一个if
块,它将在上面的代码之前执行:
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) {
...
*/
Run Code Online (Sandbox Code Playgroud)
如果package
(与上面相同)是空字符串,则会出现错误消息
ImportError: attempted relative import with no known parent package
Run Code Online (Sandbox Code Playgroud)
但是,您只能在Python 3.6或更高版本中看到这一点.
考虑一个目录(这是一个Python 包):
.
??? package
? ??? __init__.py
? ??? module.py
? ??? standalone.py
Run Code Online (Sandbox Code Playgroud)
包中的所有文件都以相同的2行代码开头:
from pathlib import Path
print('Running' if __name__ == '__main__' else 'Importing', Path(__file__).resolve())
Run Code Online (Sandbox Code Playgroud)
我只包括这两行,以使操作顺序明显.我们可以完全忽略它们,因为它们不会影响执行.
__init__.py和module.py只包含这两行(即它们实际上是空的).
standalone.py还尝试通过相对导入导入module.py:
from . import module # explicit relative import
Run Code Online (Sandbox Code Playgroud)
我们很清楚/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'>
Run Code Online (Sandbox Code Playgroud)
-m
为你做所有导入的东西并自动设置__package__
,但你可以自己做
请将其视为概念证明而非实际解决方案.它不适合在真实世界的代码中使用.
PEP 366有一个解决这个问题的方法,然而,它不完整,因为__package__
单独设置是不够的.您将需要在模块层次结构中导入至少N个前面的包,其中N是将搜索要导入的模块的父目录的数量(相对于脚本的目录).
从而,
添加当前模块的第N个前任的父目录sys.path
从中删除当前文件的目录 sys.path
使用其完全限定名称导入当前模块的父模块
设置__package__
为完全合格的名字从2
执行相对导入
我将从解决方案#1借用文件并添加更多子包:
package
??? __init__.py
??? module.py
??? subpackage
??? __init__.py
??? subsubpackage
??? __init__.py
??? standalone.py
Run Code Online (Sandbox Code Playgroud)
这次standalone.py将使用以下相对导入从包包中导入module.py
from ... import module # N = 3
Run Code Online (Sandbox Code Playgroud)
我们需要在该行之前加上样板代码,以使其工作.
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
Run Code Online (Sandbox Code Playgroud)
它允许我们通过filename 执行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
Run Code Online (Sandbox Code Playgroud)
可以在此处找到包含在函数中的更通用的解决方案.用法示例:
if __name__ == '__main__' and __package__ is None:
import_parents(level=3) # N = 3
from ... import module
from ...module.submodule import thing
Run Code Online (Sandbox Code Playgroud)
步骤是 -
用等效的绝对导入替换显式相对导入
安装package
以使其可导入
例如,目录结构可以如下
.
??? project
? ??? package
? ? ??? __init__.py
? ? ??? module.py
? ? ??? standalone.py
? ??? setup.py
Run Code Online (Sandbox Code Playgroud)
setup.py是哪里的
from setuptools import setup, find_packages
setup(
name = 'your_package_name',
packages = find_packages(),
)
Run Code Online (Sandbox Code Playgroud)
其余的文件都是从解决方案#1中借来的.
无论您的工作目录如何,安装都将允许您导入包(假设没有命名问题).
我们可以修改standalone.py来使用这个优势(步骤1):
from package import module # absolute import
Run Code Online (Sandbox Code Playgroud)
将您的工作目录更改为project
并运行/path/to/python/interpreter setup.py install --user
(--user
在您的site-packages目录中安装该软件包)(步骤2):
vaultah@base:~$ cd project
vaultah@base:~/project$ python3 setup.py install --user
Run Code Online (Sandbox Code Playgroud)
让我们验证现在可以将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'>
Run Code Online (Sandbox Code Playgroud)
注意:如果您决定沿着这条路走下去,那么最好使用虚拟环境来隔离安装软件包.
坦率地说,安装不是必需的 - 您可以在脚本中添加一些样板代码以使绝对导入起作用.
我将从解决方案#1借用文件并更改standalone.py:
的父目录添加包到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
Run Code Online (Sandbox Code Playgroud)用绝对导入替换相对导入:
from package import module # absolute import
Run Code Online (Sandbox Code Playgroud)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'>
Run Code Online (Sandbox Code Playgroud)
我觉得我应该警告你:尽量不这样做,特别是如果你的项目结构复杂的话.
作为附注,PEP 8建议使用绝对进口,但声明在某些情况下可以接受明确的相对进口:
建议使用绝对导入,因为它们通常更易读并且往往表现更好(或者至少提供更好的错误消息).[...]但是,显式相对导入是绝对导入的可接受替代方法,尤其是在处理复杂的包布局时,使用绝对导入会不必要地冗长.
am5*_*am5 60
把它放在你的包的__init__.py文件中:
# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))
Run Code Online (Sandbox Code Playgroud)
假设你的包是这样的:
??? project
? ??? package
? ? ??? __init__.py
? ? ??? module1.py
? ? ??? module2.py
? ??? setup.py
Run Code Online (Sandbox Code Playgroud)
现在在你的包中使用常规导入,例如:
# in module2.py
from module1 import class1
Run Code Online (Sandbox Code Playgroud)
这适用于python 2和3.
Mar*_*ers 51
系统错误:父模块“”未加载,无法执行相对导入
这意味着您正在将包内的模块作为脚本运行。在包内混合脚本是很棘手的,如果可能的话应该避免。使用导入包并运行您的scripty
函数的包装器脚本。
如果您的顶级目录名为foo
,位于您的PYTHONPATH
模块搜索路径上,并且您bar
在那里有一个包(它是您期望__init__.py
在其中包含文件的目录),则脚本不应放置在 内,而bar
foo
应位于最好的。
请注意,脚本与此处的模块不同,因为它们python
通过使用python <filename>
或通过#!
(shebang) 行用作命令的文件名参数。它直接作为__main__
模块加载(这就是在脚本中工作的原因if __name__ == "__main__":
),并且没有可用于相对导入的包上下文。
如果可以的话,使用setuptools
(或poetry
或flit
,这可以帮助简化打包)打包您的项目,并创建控制台脚本入口点;安装您的项目pip
然后创建知道如何正确导入包的脚本。您可以使用 本地安装您的包pip install -e .
,因此仍然可以就地编辑它。
否则,永远、永远、使用python path/to/packagename/file.py
、总是使用python path/to/script.py
和script.py
可以使用from packagename import ...
。
作为后备方案,您可以使用-m
命令行开关告诉 Python 导入模块并将其用作文件__main__
。但是,这不适用于 shebang 行,因为不再有脚本文件。
如果您使用python -m foo.bar
并foo/bar.py
在目录中找到sys.path
,则会像__main__
正确的包上下文一样导入并执行。如果bar
也是一个包,那么里面foo/
必须有一个__main__.py
文件(以及foo/bar/__main__.py
目录的路径sys.path
)。
极端情况下,直接通过设置添加Python用来解析相对导入的元数据__package__
;该文件foo/bar/spam.py
可导入为foo.bar.spam
,被赋予全局__package__ = "foo.bar"
. 它只是另一个全局变量,就像__file__
and一样__name__
,由 Python 在导入时设置。
sys.path
上述所有内容都要求您的包可以导入,这意味着它需要在 .zip 中列出的目录(或 zip 文件)之一中找到sys.path
。这里也有几个选项:
找到的目录path/to/script.py
(so path/to
)会自动添加到sys.path
. 执行python path/to/foo.py
添加path/to
到sys.path
.
如果您打包了项目(使用setuptools
、poetry
或flit
其他 Python 打包工具)并安装了它,则该包已添加到正确的位置。
作为最后的手段,请自行添加正确的目录sys.path
。如果包可以相对于脚本文件定位,则使用__file__
脚本全局命名空间中的变量(例如使用pathlib.Path
object,HERE = Path(__file__).resolve().parent
是对文件所在目录的引用,作为绝对路径)。
小智 32
我遇到了这个问题.黑客解决方法是通过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()
Run Code Online (Sandbox Code Playgroud)
wol*_*evo 28
长话短说
您只能相对导入同一包中另一个模块内的模块。
概念澄清
我们在书籍/文档/文章中看到很多示例代码,它们向我们展示了如何相对导入模块,但是当我们这样做时,它会失败。
原因是,简单来说,我们没有按照Python模块机制期望的方式运行代码,尽管代码写得完全正确。这就像某种运行时的东西。
模块加载取决于您运行代码的方式。这就是混乱的根源。
什么是模块?
当且仅当模块被另一个文件导入时,它才是一个 python 文件。给定一个文件mod.py
,它是一个模块吗?是和否,如果您运行python mod.py
,它不是一个模块,因为它没有导入。
什么是包裹?
包是包含 Python 模块的文件夹。
顺便说一句,__init__.py
如果您不需要任何包初始化或自动加载子模块,则从 python 3.3 开始就不需要了。您不需要__init__.py
在目录中放置空白。
这证明只要有文件被导入,包就只是一个文件夹。
真实答案
现在,这个描述变得更加清晰。
您只能相对导入同一包中另一个模块内的模块。
给定一个目录:
. CWD
|-- happy_maker.py # content: print('Sends Happy')
`-- me.py # content: from . import happy_maker
Run Code Online (Sandbox Code Playgroud)
跑吧python me.py
,我们得到了attempted relative import with no known parent package
me.py
是直接运行的,它不是一个模块,我们不能在其中使用相对导入。
解决方案1
使用import happy_maker
而不是from . import happy_maker
解决方案2
将我们的工作目录切换到父文件夹。
. CWD
|-- happy
| |-- happy_maker.py
`-- me.py
Run Code Online (Sandbox Code Playgroud)
跑步python -m happy.me
。
happy
当我们在包含、happy
是包、是模块的目录中时me.py, happy_maker.py
,我们现在可以使用相对导入,但我们仍然想运行me.py
,所以我们使用-m
这意味着将模块作为脚本运行。
Python 习语
. CWD
|-- happy
| |-- happy_maker.py # content: print('Sends Happy')
| `-- me.py # content: from . import happy_maker
`-- main.py # content: import happy.me
Run Code Online (Sandbox Code Playgroud)
这个结构就是Python的习惯用法。main
是我们的脚本,Python 中的最佳实践。终于,我们到了那里。
兄弟姐妹或祖父母
另一个常见的需求:
.
|-- happy
| |-- happy_maker.py
| `-- me.py
`-- sad
`-- sad_maker.py
Run Code Online (Sandbox Code Playgroud)
我们想要导入sad_maker
进来me.py
,怎么做呢?
首先,我们需要将happy
和sad
放在同一个包中,因此我们必须上一级目录。然后from ..sad import sad_maker
在me.py
.
就这些。
Gra*_*ell 16
对于 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 的解析器。这是错误的,尽管它说了什么,但代码运行良好。
SeF*_*SeF 14
pathlib
库更新,并适用于__file__
未定义的 Jupyter 笔记本:您需要
根据编写代码的位置导入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
Run Code Online (Sandbox Code Playgroud)
fra*_*lau 12
为了避免这个问题,我设计了一个带有repackage包的解决方案,它对我有用了一段时间。它将上层目录添加到 lib 路径中:
import repackage
repackage.up()
from mypackage.mymodule import myfunction
Run Code Online (Sandbox Code Playgroud)
使用智能策略(检查调用堆栈),重新打包可以使相对导入适用于各种情况。
And*_*dor 11
我的样板是在可运行的独立文件中制作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
...
Run Code Online (Sandbox Code Playgroud)
现在您可以以任何方式使用您的模块:
python -m package.module
python -c 'from package import module'
python package/module.py
#!/bin/env python
) 只是:package/module.py
注意!sys.path.append
如果sys.path.insert
您的名称module
与您的package
. 例如my_script/my_script.py
当然,如果您有来自包层次结构中更高级别的相对导入,那么这还不够,但对于大多数情况来说,这是可以的。
首先,您可以从同一目录导入。
\n这是文件结构...
\nFolder\n |\n \xe2\x94\x9c\xe2\x94\x80 Scripts\n | \xe2\x94\x9c\xe2\x94\x80 module123.py\n |\n \xe2\x94\x9c\xe2\x94\x80 main.py\n \xe2\x94\x9c\xe2\x94\x80 script123.py\n
Run Code Online (Sandbox Code Playgroud)\n这是main.py
\nFolder\n |\n \xe2\x94\x9c\xe2\x94\x80 Scripts\n | \xe2\x94\x9c\xe2\x94\x80 module123.py\n |\n \xe2\x94\x9c\xe2\x94\x80 main.py\n \xe2\x94\x9c\xe2\x94\x80 script123.py\n
Run Code Online (Sandbox Code Playgroud)\n如您所见,从.
当前目录导入。
\n\n注意:如果使用除 IDLE 以外的任何方式运行,请确保
\nmain.py
在运行之前将终端导航到与文件相同的目录。
此外,从本地文件夹导入也可以。
\n正如我在 GitHub gist中看到的,有以下方法。
\n采取以下文件树...
\nParentDirectory\n \xe2\x94\x9c\xe2\x94\x80 Folder\n | |\n | \xe2\x94\x9c\xe2\x94\x80 Scripts\n | | \xe2\x94\x9c\xe2\x94\x80 module123.py\n | |\n | \xe2\x94\x9c\xe2\x94\x80 main.py\n | \xe2\x94\x9c\xe2\x94\x80 script123.py\n |\n \xe2\x94\x9c\xe2\x94\x80 parentModule.py\n
Run Code Online (Sandbox Code Playgroud)\n然后,只需将此代码添加到文件顶部即可main.py
。
from . import script123\nfrom Scripts import module123\n
Run Code Online (Sandbox Code Playgroud)\n
我需要从主项目目录运行 python3 才能使其工作。
例如,如果项目具有以下结构:
project_demo/
??? main.py
??? some_package/
? ??? __init__.py
? ??? project_configs.py
??? test/
??? test_project_configs.py
Run Code Online (Sandbox Code Playgroud)
我会在文件夹project_demo/ 中运行 python3 ,然后执行
from some_package import project_configs
Run Code Online (Sandbox Code Playgroud)
小智 6
希望这对那里的某人有价值-我浏览了六堆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'
Run Code Online (Sandbox Code Playgroud)
但是,当我明确指定路径时,事情开始起作用:
$ PYTHONPATH=. python3 test/my_module/module_test.py 2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s
OK
Run Code Online (Sandbox Code Playgroud)
因此,如果有人尝试了一些建议,则认为他们的代码结构正确,并且如果您不将当前目录导出到PYTHONPATH,则仍然遇到与我类似的情况:
$ PYTHONPATH=. python3 test/my_module/module_test.py
PYTHONPATH=.
,请创建一个setup.py
内容如下的文件,然后运行python setup.py development
以将软件包添加到路径中:Run Code Online (Sandbox Code Playgroud)# setup.py from setuptools import setup, find_packages setup( name='sample', packages=find_packages() )
小智 6
我尝试了上述所有方法均无济于事,才意识到-
我的包名称中错误地包含了 a 。
-
简而言之,就是所在目录下没有__init__.py
。在发现如此愚蠢的事情后,我从未感到高兴。
对于那些不同意Guido的人来说,这里有三句话:
import sys
from pathlib import Path
sys.path.append(str(Path(sys.argv[0]).absolute().parent.parent))
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你。
更新:发现当通过相对路径调用可执行文件时,此操作会失败。解决方案是使用resolve()
而不是absolute()
:
import sys
from pathlib import Path
sys.path.append(str(Path(sys.argv[0]).resolve().parent.parent))
Run Code Online (Sandbox Code Playgroud)
我收到了这个导入错误:尝试相对导入而没有已知的父包
在我的程序中,我使用当前路径中的文件来导入其功能。
from .filename import function
Run Code Online (Sandbox Code Playgroud)
然后我用包名修改了当前路径(点)。这解决了我的问题。
from package_name.filename import function
Run Code Online (Sandbox Code Playgroud)
希望以上回答对你有帮助。
归档时间: |
|
查看次数: |
379502 次 |
最近记录: |