17370845950

如何检测当前 Python 是否运行在 Pyodide(浏览器)环境中
Pyodide环境可通过检测window.pyodide存在且为对象,或sys.platform=="emscripten"来可靠识别;需同时排除Electron、Node.js等干扰环境,避免仅依赖window或sys.implementation.name。

检查 windowpyodide 全局对象是否存在

Pyodide 运行在浏览器 Web Worker 或主线程中,会向全局作用域注入 window(或 self)和 pyodide 对象。最直接的判断方式是检测这两个标识符是否可访问且类型正确:

  • window 存在且为 object(排除 Node.js 或纯 CLI 环境)
  • window.pyodide 存在且为对象(不是 undefinednull
  • 避免仅检查 window —— 比如 Electron、NW.js 也有 window,但不是 Pyodide

实操建议:

def is_pyodide():
    try:
        import sys
        if "pyodide" in sys.modules:
            return True
        # fallback: check global JS scope
        from js import window
        return hasattr(window, "pyodide") and window.pyodide is not None
    except (ImportError, Att

ributeError): return False

利用 sys.platformsys.implementation.name 辅助识别

Pyodide 的 sys.platform 固定为 "emscripten"sys.implementation.name"cpython"(注意:不是 "pyodide"),这点和 CPython 本体不同但和 Emscripten 编译目标一致。

  • sys.platform == "emscripten" 是强信号,几乎只出现在 Pyodide / Emscripten 环境
  • 单独依赖 sys.implementation.name == "cpython" 不可靠 —— 标准 CPython 也返回这个值
  • 组合使用更稳妥:sys.platform == "emscripten" + "pyodide" in sys.modules

避免误判:Node.js、Jest、Electron 的干扰项

有些环境也会暴露 window 或模拟浏览器 API,导致简单判断出错:

  • Jest 测试环境可能有 window,但没有 pyodide 对象
  • Electron 主进程无 window,渲染进程有 window 但无 pyodide
  • Node.js 里 globalThis.windowundefined,但某些 polyfill 库可能挂载空对象

因此必须把 pyodide 对象存在性作为必要条件,而不是仅靠运行时平台字符串或全局变量名。

生产代码中推荐的健壮检测函数

综合上述,一个低侵入、不抛异常、兼容导入时机的检测方式:

def is_pyodide():
    try:
        from js import window
        if hasattr(window, "pyodide") and window.pyodide:
            return True
    except ImportError:
        pass
    try:
        import sys
        if sys.platform == "emscripten":
            return True
    except AttributeError:
        pass
    return False

注意:该函数在非浏览器环境(如本地 Python)中不会触发 js 模块导入失败以外的副作用;is_pyodide() 返回 True 时,基本可以安全调用 pyodide.loadPackage 或读取 js.document —— 但别忘了,js 模块本身只在 Pyodide 初始化完成后才可用,所以首次检测最好放在 main() 或事件回调中,而非模块顶层。