Logo
    打开 Gandi IDE
    Python in Gandi 技术实现
    Python in Gandi 技术实现

    Python in Gandi 技术实现

    💡返回博客
    ‣
    更多链接
    🤹
    如果想了解 Python in Scratch / Gandi 的 背景,请先阅读 🐍Python in Scratch/Gandi 综述

    Python 语言能力

    Python 作为一种动态脚本语言,相对其他语言有如下优势:

    1. 适用范围广(Tuibe 排行第一)
    2. 入门门槛低
    3. 强大的标准库
    4. 扩展性强(通过 C/C++ 可以方便引入 Native Module)
    5. 语法灵活(生成器、装饰器、内省、协程等)

    对比 JavaScript

    1. 更多的数据类型
    2. 更广泛的的标准库以及第三方模块
    3. 更高级的语法特性

    示例

    在Python中实现一个快排算法

    def quick_sort(arr):
        if len(arr) <= 1:
            return arr
        else:
            pivot = arr[0]
            less = [x for x in arr[1:] if x <= pivot]
            greater = [x for x in arr[1:] if x > pivot]
            return quick_sort(less) + [pivot] + quick_sort(greater)

    只是为了排序功能,也可以直接调用标准库

    arr.sort()
    # or sorted(arr)

    Python Runtime 实现

    Python in Browser

    Gandi 的主要场景是在浏览器中运行,如果将Python集成进来,则需要解决如何在浏览器中运行 Python 的问题。比较常见的方案有:

    1. 将 Python 编译成 JavaScript,代表是 Brython、Skulpt
    2. CPython 运行时 编译成 WebAssembly,代表是 Pyodide
    由于 Skulpt 只支持 Python 2.x,这里主要对比 Pyodide 和 Brython:
    Brython
    Pyodide
    开发活跃度
    活跃
    活跃
    语言能力完备性
    较完备
    完备
    最新支持版本
    3.11
    3.10
    标准库支持
    支持
    支持
    第三方模块
    支持 Pure-Python 模块
    支持 Pure-Python 模块以及 C/C++ Extension 模块
    调用 ECMAScript
    支持
    支持
    操作 DOM
    支持
    支持
    类型映射
    无需映射
    需要类型映射
    License
    BSD 3
    MPL 2.0

    Pyodide 由于 Runtime 实现是基于 CPython,因此语言能力更接近原生的 Python,同时也支持调用浏览器 ECMAScript、DOM(理论上未来可以直接在 Python 中调用 Scratch 的 Runtime 和 Render)。

    综上,采用 Pyodide 作为 Python in Browser 的技术选型。

    运行架构

    为了避免 Python Runtime 阻塞 Scratch VM 执行线程,采用 WebWorker 架构来并行的执行 Python 脚本
    image

    能力限制(对比CPython)

    1. 不支持的模块
    2. distutils、ssl、lzma、sqlite3

      curses、dbm、ensurepip、idlelib、lib2to3、tkinter、turtle.py、turtledemo、venv、pwd

    3. 功能不完整的模块
    4. multiprocessing、threading、sockets

    安全性

    由于 Python 强大的语法特性(不像 Scratch 只提供了有限的能力),其创作的 Scratch 作品会运行在所有玩家的浏览器上,因此还需要考虑脚本的安全性,避免恶意脚本。

    1. 基于 Browser + WebAssembly 的沙箱机制
      1. 没有多线程、多进程、Socket等模块能力
      2. 对文件系统的访问是抽象可限制的(当前提供的是 MemFS + WorkerFS)
      3. 无法进行系统调用
    2. 独立的 WebWorker 限制了 JavaScript 的作用域
    3. 暂时限制了 Pyodide VM 层对 JS 的调用,屏蔽了 pyodide 内置的但 不安全的模块

    抽象文件系统

    在 Python 中如果需要访问项目中的资源文件(目前开放支持了 JSON 等文本类型文件)、或者 import 其他 Python 文件,则需要构建一个抽象的文件系统。

    我们使用 Emscripten 的 FileSystem API,将项目中的 Assets 手动挂载到 FS 中,这样即可以通过 open 等系统调用访问文件内容。由于是 WorkerFS 的特性,文件内容也是只读的。

    关于 WorkerFS 的实现原理参考 emscripten/library_workerfs.js
    let mountDir = "/project";
    self.pyodide.FS.mkdir(mountDir);
    self.pyodide.FS.mount(self.pyodide.FS.filesystems.WORKERFS, {
      blobs: fs.map(f => {
        return {
          name: f.name,
          data: new Blob([f.data]),
        }
      }),
    }, mountDir);
    self.pyodide.FS.chdir(mountDir);

    除了这里手动挂载的资源目录,外部的根文件系统 / 使用的是默认的 MemFS。即所有的文件存在于内存中,写入的文件内容在页面重新加载后会丢失。

    文本编辑器

    为了方便地在 Gandi IDE 中编写 Python 脚本,这里还需要在前端引入一套文本编辑器组件,针对它的选型,主要考虑以下几点:

    1. 开源且开发活跃
    2. 适用范围广、大量应用于生产环境
    3. 扩展性强(支持 Language Server 和 Collaborative Editing)

    综合考虑,选用 Monaco Editor

    Language Server

    为了更好的接近原生的 VSCode/IDE 编辑体验,我们基于 Language Server Protocol,实现了在编辑器中 Python 脚本的高级编辑能力:

    1. 代码补全提示
    2. image
    3. 语法或代码风格检测
    4. image
    5. 高亮和格式化
    6. image
    7. 跳转定义和查找引用
    8. image

    架构图

    image
    这里更优的实现方式可能是用 WebAssembly 实现 Language Server,通过嵌入到 WebWorker 与 Monaco Editor 进行通信,以减少对服务端的依赖和降低请求延迟。新的架构目前已经在技术预研阶段,并将在不久后开源。

    协作?

    目前该文本编辑器暂不支持协作,相关研发已经在规划中。

    FAQ

    1. 脚本执行会保存状态吗?
    2. 会的。单个脚本的多次脚本执行使用同一个 VM,即是可以在脚本里保存运行状态。比如多次调用可以共享同一组全局变量。

    3. 支持加载外部第三方扩展吗?
    4. 暂未开放。后续会根据用户反馈情况逐步白名单开放。

    5. 支持脚本之间相互 import 吗?
    6. 支持。比如 a.py 需要 import b.py 的方法 add,可以使用直接使用 from b import add。

    7. 支持在脚本中直接读写 Scratch 里面的变量吗?
    8. 暂不支持。为了和 Scratch VM有较好的解耦合,避免在脚本内部隐形操作变量导致项目维护成本变高,暂时不支持直接读写变量,而是手动通过值积木在外层传值和赋值。

    9. 支持脚本操作舞台吗?
    10. 暂不支持。具体原因同上。

    11. 可以写爬虫吗?
    12. 不行。为了安全考虑,暂不会放开网络库(urllib, requests等)以及提供其他类似库。

    icon
    Cappu

    共创世界 开发团队后端负责人。在 Gandi IDE 团队参与到后端服务、Gandi Engine相关架构与研发。

    ✉️ dudongcheng@ccw.site | 飞书链接

    <iframe
    	width="100%"
    	height="800px"
    	scrolling="no"
    	src="https://www.ccw.site/embed?id=blog/posts/tech-behind-python-in-gandi&type=comment"
    	title="Python in Gandi 技术实现"
    	frameBorder="0"
    	allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    	allowFullScreen
    ></iframe>

    本页索引

    • Python 语言能力
    • 对比 JavaScript
    • 示例
    • Python Runtime 实现
    • Python in Browser
    • 运行架构
    • 能力限制(对比CPython)
    • 安全性
    • 抽象文件系统
    • 文本编辑器
    • Language Server
    • FAQ
    Gandi IDE 🧑‍💻 开发者中心 @ 共创世界

    Designed by 2ndR with love @ Chengdu

    Tencent QQGitHub