You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将Python包合并为单脚本时遇相对导入错误求助

解决PyBreeder生成脚本中的相对导入错误(ImportError: attempted relative import with no known parent package)

问题背景

尝试用PyBreeder将Python包与二进制文件合并为单脚本,该工具原针对Python2开发,虽有适配Python3的PR可生成脚本,但运行生成的脚本时触发错误:

ImportError: attempted relative import with no known parent package

复现步骤

  • 创建trying目录,包含__init__.py和app.py文件:
    • __init__.py内容:
      from .app import *
      
    • app.py内容:
      def hello():
          print("nice")
      
  • 执行命令生成脚本:
    python breeder.py trying/ > generated.py
    
  • 运行生成的脚本python generated.py,触发上述错误。

错误原因

生成的脚本存在两个核心问题:

  1. 仅创建了trying模块,但未设置__package__属性,导致相对导入from .app import *无法识别父包上下文。
  2. 未加载app.py的内容到内存模块中,即使修复包属性,也找不到trying.app模块。

修复方案

修改生成的脚本,补充模块初始化逻辑:

修改后的完整脚本

#!/usr/bin/python

import base64, os, sys, zlib
try:
    import io as StringIO
except ImportError:
    import StringIO
if sys.version_info >= (3, 4):  # 修正错误的版本判断条件
    from importlib.util import module_from_spec as new_module
else:
    import warnings
    with warnings.catch_warnings():
        warnings.filterwarnings("ignore",category=DeprecationWarning)
        from imp import new_module
__FILES = {}
__builtin_open = open
__os_path_exists, __os_path_getsize = os.path.exists, os.path.getsize
def __comb_open(filename, *args, **kwargs):
    if filename in __FILES:
        return StringIO.StringIO(__FILES[filename])
    else:
        return __builtin_open(filename, *args, **kwargs)
def __comb_exists(filename, *args, **kwargs):
    if filename in __FILES:
        return True
    else:
        return __os_path_exists(filename, *args, **kwargs)
def __comb_getsize(filename, *args, **kwargs):
    if filename in __FILES:
        return len(__FILES[filename])
    else:
        return __os_path_getsize(filename, *args, **kwargs)
if 'b64decode' in dir(base64):
    __b64d = base64.b64decode
else:
    __b64d = base64.decodestring
open = __comb_open
os.path.exists = __comb_exists
os.path.getsize = __comb_getsize
sys.path[0:0] = ['.SELF/']

###############################################################################
# 先加载并初始化trying.app模块
__FILES[".SELF/trying/app.py"] = """\
def hello():
    print("nice")
"""
app_mod = sys.modules["trying.app"] = new_module("trying.app")
app_mod.__file__ = "trying/app.py"
app_mod.__package__ = "trying"
app_mod.open = __comb_open
exec(__FILES[".SELF/trying/app.py"], app_mod.__dict__)

# 再初始化trying模块并设置__package__属性
__FILES[".SELF/trying/__init__.py"] = """\
from .app import *
"""
m = sys.modules["trying"] = new_module("trying")
m.__file__ = "trying/__init__.py"
m.__package__ = "trying"  # 新增属性,支持相对导入
m.open = __comb_open
exec(__FILES[".SELF/trying/__init__.py"], m.__dict__)

###############################################################################

def hello():
    print("nice")


#EOF#

关键修改点

  1. 修正版本判断:将原错误的(999, 3, 4)改为(3,4),确保Python3环境下正确导入模块工具。
  2. 预加载子模块:先创建trying.app模块并初始化,保证父模块导入时能找到子模块。
  3. 设置__package__属性:为trying和trying.app模块添加该属性,提供相对导入的上下文。

验证

运行修改后的脚本,执行以下代码可正常输出:

from trying import hello
hello()  # 输出: nice

内容的提问来源于stack exchange,提问作者Mhmd Admn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 22:10:31