Files
NebulaShell/website/docs/why-python.html
2026-04-06 17:03:11 +08:00

160 lines
8.4 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>为什么选择 Python - Future OSS 文档</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="../css/main.css" />
<link rel="stylesheet" href="../css/dock.css" />
<link rel="stylesheet" href="../css/docs.css" />
</head>
<body>
<canvas id="particles"></canvas>
<div id="dock-container"></div>
<main class="page-docs">
<header class="docs-header">
<button class="docs-hamburger" id="docs-hamburger" aria-label="切换导航菜单">
<span class="docs-hamburger-line"></span>
<span class="docs-hamburger-line"></span>
<span class="docs-hamburger-line"></span>
</button>
<div class="docs-header-title">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" width="22" height="22">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/>
</svg>
<span>文档中心</span>
</div>
<div class="docs-header-breadcrumb">入门 · 为什么用Python</div>
<div class="docs-header-actions">
<a href="https://gitee.com/starlight-apk/feature-oss/wikis" target="_blank" class="docs-wiki-link">完整 Wiki</a>
</div>
</header>
<div class="docs-sidebar-overlay" id="docs-overlay"></div>
<div class="docs-layout">
<aside class="docs-sidebar" id="docs-sidebar">
<div class="docs-nav-section">
<div class="docs-nav-section-title">入门</div>
<a href="index.html" class="docs-nav-item">什么是 FutureOSS<span class="nav-path">/ 项目介绍</span></a>
<a href="why-python.html" class="docs-nav-item active">为什么选择 Python<span class="nav-path">/ 技术选型</span></a>
<a href="architecture.html" class="docs-nav-item">架构设计<span class="nav-path">/ 三层架构</span></a>
</div>
<div class="docs-nav-section">
<div class="docs-nav-section-title">快速开始</div>
</div>
<div class="docs-nav-section">
<div class="docs-nav-section-title">插件</div>
<a href="plugins.html" class="docs-nav-item">官方插件列表<span class="nav-path">/ 12+ 插件</span></a>
<a href="development.html" class="docs-nav-item">插件开发指南<span class="nav-path">/ 开发基础</span></a>
</div>
</aside>
<div class="docs-content-wrapper">
<article class="docs-content">
<h1>🐍 为什么从 Go 重构为 Python</h1>
<p>Go 的 <code>plugin</code> 包不适合热插拔场景。<code>.so</code> 文件与主程序是独立编译单元,类型不共享,依赖注入后接口不匹配会导致 <code>panic</code>。Python 的动态特性天然适合插件化架构。</p>
<h2>技术对比</h2>
<table>
<thead>
<tr><th>问题</th><th>Go 方案</th><th>Python 方案</th></tr>
</thead>
<tbody>
<tr><td>插件热插拔</td><td><code>plugin.Open(".so")</code></td><td><code>importlib</code> 动态加载 <code>.py</code></td></tr>
<tr><td>依赖注入</td><td>反射注入,类型不匹配 → panic</td><td>直接传 dict/对象,无编译隔离</td></tr>
<tr><td>开发效率</td><td>每次改插件需重新编译</td><td>改完即生效,零编译</td></tr>
<tr><td>配置类型</td><td><code>map[string]string</code> 限制</td><td><code>dict[str, Any]</code> 原生支持任意类型</td></tr>
</tbody>
</table>
<h2>Go 插件系统的致命问题</h2>
<p>Go 的插件机制依赖 <code>plugin.Open()</code> 加载编译好的 <code>.so</code> 文件。每个 <code>.so</code> 是独立的编译单元,无法共享类型定义。这意味着插件中定义的接口与框架中的接口即使签名相同,也被视为不同类型,导致依赖注入后接口为 <code>nil</code>,运行时直接 <code>panic</code></p>
<h2>Python 的优势</h2>
<ul>
<li><strong>动态类型</strong> — 没有编译时类型检查,插件直接使用框架定义的类型</li>
<li><strong>importlib</strong> — 运行时动态加载 <code>.py</code> 文件,零编译开销</li>
<li><strong>类型共享</strong> — 插件通过 <code>from oss.plugin.types import Plugin</code> 直接引用框架类型</li>
<li><strong>开发迭代快</strong> — 改完代码即生效,无需重新编译</li>
</ul>
</article>
</div>
</div>
</main>
<a href="https://gitee.com/starlight-apk/feature-oss/wikis" target="_blank" class="docs-wiki-btn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/>
</svg>
<span>获取更多信息</span>
</a>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
<script src="../js/dock.js"></script>
<script src="../js/particles.js"></script>
<script src="../js/parallax.js"></script>
<script src="../js/animations.js"></script>
<script>
// 汉堡菜单交互逻辑
(function() {
const hamburger = document.getElementById('docs-hamburger');
const sidebar = document.getElementById('docs-sidebar');
const overlay = document.getElementById('docs-overlay');
if (!hamburger || !sidebar || !overlay) return;
function openSidebar() {
sidebar.classList.add('is-open');
overlay.classList.add('is-visible');
hamburger.classList.add('is-active');
document.body.style.overflow = 'hidden';
}
function closeSidebar() {
sidebar.classList.remove('is-open');
overlay.classList.remove('is-visible');
hamburger.classList.remove('is-active');
document.body.style.overflow = ''';
}
function toggleSidebar() {
if (sidebar.classList.contains('is-open')) {
closeSidebar();
} else {
openSidebar();
}
}
hamburger.addEventListener('click', toggleSidebar);
overlay.addEventListener('click', closeSidebar);
sidebar.querySelectorAll('.docs-nav-item).forEach(link => {
link.addEventListener('click', closeSidebar);
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && sidebar.classList.contains('is-open')) {
closeSidebar();
}
});
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
if (window.innerWidth > 768 && sidebar.classList.contains('is-open')) {
closeSidebar();
}
}, 100);
});
})();
</script>
</body>
</html>