python - 我得到 SystemError: Parent module '' not loaded, cannot perform relative import Error when I run my Python Script
问题描述
我的ipmi_server.py
文件如下:
#!/usr/bin/python3
#-*- coding:utf-8 -*-
# Author: dele
import socket
from .ipmi_util import ipmi_handler
from .allowed_ip import allowed_ip_list
HOST = '4.24.124.29'
PORT = 65432
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
while True:
conn, addr = s.accept()
with conn:
print('Connected by', addr)
if addr and addr[0] not in allowed_ip_list:
conn.sendall('invalid ip')
else:
while True:
data = conn.recv(1024)
if not data:
break
当我运行 ipmi_server.py 文件时,出现以下错误:
dele-MBP:ipmi_management ldl$ python3 ipmi_server.py
Traceback (most recent call last):
File "ipmi_server.py", line 7, in <module>
from .ipmi_util import ipmi_handler
SystemError: Parent module '' not loaded, cannot perform relative import
目录树如下:
我检查了帖子,但没有找到解决方案。
--
EDIT-01
我试过了
from ipmi_management.ipmi_util import ipmi_handler
但得到以下错误:
dele-MBP:ipmi_management ldl$ python3 ipmi_server.py
Traceback (most recent call last):
File "ipmi_server.py", line 7, in <module>
from ipmi_management.ipmi_util import ipmi_handler
ImportError: No module named 'ipmi_management'
解决方案
如果直接运行 ipmi_server,则不能使用相对导入。
原因是相对导入是相对于__name__
当前文件使用的。
模块的
__name__
设置等于__main__
从标准输入、脚本或交互式提示读取时。
您将模块作为脚本运行,因此相对导入将不起作用。
您可以从项目的根文件夹中将其作为包运行(注意这是作为包执行的,因此我省略了.py
扩展名)
python -m ipmi_management.ipmi_server
或者用此处记录的绝对导入替换相对导入:
from ipmi_management.ipmi_util import ipmi_handler
编辑-01
正如这个答案中所解释的那样,这只有在您以交互方式导入脚本时才有效。
从命令行执行脚本时, sys.path[0] 将等于包含您正在执行的模块的目录的路径。即使同样从项目根目录运行模块:python ipmi_management/ipmi_server.py
也没有什么区别。
例如,如果您的模块位于:
/home/user/projects/qiyun_ipmi_management/ipmi_management/ipmi_server.py', sys.path[0] would be equal to
/home/user/projects/qiyun_ipmi_management/ipmi_management/'
如此处所述,python 导入的工作方式,解释器根本不知道在哪里可以找到ipmi_management
包。
虽然我建议的第一个选项仍然有效,但不建议从包中运行模块,您应该调整项目以允许将ipmi_management
其用作包:
将代码更改ipmi_server.py
如下:
def run_server():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
while True:
conn, addr = s.accept()
with conn:
print('Connected by', addr)
if addr and addr[0] not in allowed_ip_list:
conn.sendall('invalid ip')
else:
while True:
data = conn.recv(1024)
if not data:
break
将一个__main__.py
模块添加到您的ipmi_management
包中,然后使用如下ipmi_server.py
代码:
from ipmi_management.ipmi_server import run_server
def main():
run_server()
if __name__ == '__main__':
main()
python -m ipmi_management
从项目根目录运行将导致调用 ipmi_server.py 并运行服务器。
请注意,我仍然使用PEP-8推荐的绝对导入
建议使用绝对导入,因为如果导入系统配置不正确(例如当包内的目录最终位于 sys.path 上时),它们通常更具可读性并且往往表现更好(或至少提供更好的错误消息):
如果您真的希望ipmi_server.py
直接运行该模块,您可以使用将该模块的父目录插入到 sys.path 中,但这被认为是非 Python 的并且通常是一个坏习惯,因为它会使 Python 导入系统更加晦涩难懂。