ImportError: attempted relative import with no known parent package

python中的relative import使用起来却有不少问题。

比如下面这样一个结构

crawler
|_src_
 |    |_spiders_
 |             |_test.py
 |
 |_local_settings.py

 

test.py中想import local_settings这个模块,那在test.py中加上

import ...local_settings

运行 python test.py。 结果就是报了标题的错误。

查阅了一些资料,原因如下:

在python文档https://docs.python.org/3.9/tutorial/modules.html#intra-package-references中有段话:

Note that relative imports are based on the name of the current module. Since the name of the main module is always "main", modules intended for use as the main module of a Python application must always use absolute imports.

还有在PEP 328(https://peps.python.org/pep-0328/#relative-imports-and-name)有:

Relative imports use a module's name attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to 'main') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

也就是说由于test.py中的__name__ attribute没有设置,__name__ == __main__,所以把test.py当成了顶层,这时reletive import就没法使用了。

解决方法有一:

sys.path.append("../..")

from local_setting import *

二:

不是直接运行test.py这个script,而是当作module来运行

python -m crawler.src.spiders.test

 三:

 不能从顶级模块中的py中使用relieve import,在 https://docs.python.org/3/tutorial/modules.html#packages中有

 Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.

请注意,相对导入是基于当前模块的名称。由于主模块的名称始终是"__main__",所以要作为 Python 应用程序主模块使用的模块必须始终使用绝对导入。

具体的分析过程参照:

https://stackoverflow.com/questions/30669474/beyond-top-level-package-error-in-relative-import

https://stackoverflow.com/questions/14132789/relative-imports-for-the-billionth-time/14132912#14132912

https://stackoverflow.com/questions/16981921/relative-imports-in-python-3

https://stackoverflow.com/questions/68960171/python-error-importerror-attempted-relative-import-with-no-known-parent-package

https://napuzba.com/a/import-error-relative-no-parent/

==============

在bypy项目下直接运行python bypy.py,也直接报这个错

复制代码
(venv) (base) gaoxianghu@gaoxiangs-MacBook-Pro bypy % python ./bypy/bypy.py
__file__=/Users/gaoxianghu/git/bypy/bypy/struct.py | __name__=struct               | __package__=                    
Traceback (most recent call last):
  File "./bypy/bypy.py", line 65, in <module>
    import pickle
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/pickle.py", line 33, in <module>
    from struct import pack, unpack
  File "/Users/gaoxianghu/git/bypy/bypy/struct.py", line 11, in <module>
    from .util import iswindows
ImportError: attempted relative import with no known parent package
复制代码
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))

可以看到__name__=struct,__package__没有信息,因为name里没有包含‘.’,表示不在package里,relative import只能用在package里,所以报:

attempted relative import with no known parent package

 However, if your module's name is __main__, it is not considered to be in a package. 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.

Scripts can't import relative

What you probably did is you tried to run moduleX or the like from the command line. When you did this, its name was set to __main__, which means that relative imports within it will fail, because its name does not reveal that it is in a package.

 

让我们看看python解释器是如何解析相关模块。从 PEP 328 中,我们找到了关于 the relative imports(相对引用)的介绍:

Relative imports use a module’s __name__ attribute to determine that module’s position in the package hierarchy. If the module’s name does not contain any package information (e.g. it is set to __main__ ) then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

相对导入通过使用模块的 __name__ 属性来确定模块在包层次结构中的位置。如果该模块的名称不包含任何包信息(例如,它被设置为 __main__ ),那么相对引用会认为这个模块就是顶级模块,而不管模块在文件系统上的实际位置。

posted @   zjhgx  阅读(2843)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
点击右上角即可分享
微信分享提示