首页 > 解决方案 > 我得到 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'

标签: python

解决方案


如果直接运行 ipmi_server,则不能使用相对导入。

原因是相对导入是相对于__name__当前文件使用的。

参考官方python文档

模块的__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 导入系统更加晦涩难懂。


推荐阅读