langShiftlangShift

Python 模塊系統與項目組織

從 JavaScript 開發者視角學習 Python 的模塊系統、包管理和項目組織最佳實踐

1. 引言

為什麼需要模塊系統?

在前端開發中,我們已經習慣了使用 ES6 模塊或 CommonJS 來組織代碼。Python 也有自己的模塊系統,雖然語法不同,但核心概念是相似的。

模塊化的核心價值

  • 代碼複用:避免重複編寫相同的功能
  • 命名空間隔離:避免變量名衝突
  • 項目組織:將相關功能組織在一起
  • 依賴管理:明確項目依賴關係

💡 學習策略:將 Python 的模塊系統理解為 JavaScript 模塊系統的"方言版本"

2. Python 模塊系統基礎

2.1 什麼是模塊?

在 Python 中,任何 .py 文件都可以作為一個模塊。這類似於 JavaScript 中的單個 .js 文件。

正在載入編輯器...

擴展閱讀:all

2.2 導入模塊的方式

Python 提供了多種導入模塊的方式,每種都有其適用場景。

正在載入編輯器...

導入方式對比表

功能JavaScriptPython說明
導入整個模塊import * as Moduleimport modulePython 更簡潔
命名導入import { func }from module import func語法不同但概念相同
重命名import { func as newName }from module import func as newName兩者都支持
默認導入import defaultFunc無對應概念Python 沒有默認導出
命名空間導入import * as Namespaceimport module as namespace概念相同

2.3 模塊的特殊變量

Python 模塊有一些特殊的變量,類似於 JavaScript 中的一些全局變量。

正在載入編輯器...

2.4 運行模塊:腳本 vs 模塊

這是 Python 初學者最容易困惑的地方之一:如何正確運行一個 Python 文件?

直接運行 vs 模塊運行

運行方式命令sys.path (搜索路徑)__name__適用場景
腳本運行python file.py包含 file.py 所在的目錄"__main__"簡單的單文件腳本
模塊運行python -m package.module包含當前工作目錄"__main__"項目中的模塊,需要引用同級或上級包時

常見錯誤示例

假設目錄結構如下:

project/
├── main.py
└── utils.py

如果在 main.py 中有 from . import utils (相對導入):

  • 運行 python project/main.py報錯ImportError: attempted relative import with no known parent package
  • 運行 python -m project.main (在 project 的上一級目錄) 會成功

💡 最佳實踐:在開發項目時,習慣在項目根目錄使用 python -m package.module 的方式運行代碼,這樣可以確保 sys.path 正確,且相對導入能正常工作。

3. 包(Package)系統

3.1 什麼是包?

包是包含多個模塊的目錄,類似於 JavaScript 中的 npm 包或目錄結構。

正在載入編輯器...

3.2 包的導入和使用

正在載入編輯器...

4. 項目組織最佳實踐

4.1 項目目錄結構

一個良好的項目結構對於代碼維護和團隊協作至關重要。

正在載入編輯器...

4.2 依賴管理對比

// package.json (JavaScript)
{
"name": "my-project",
"version": "1.0.0",
"description": "A sample project",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"test": "jest",
"build": "webpack",
"dev": "nodemon src/index.js"
},
"dependencies": {
"express": "^4.18.2",
"axios": "^1.6.0",
"lodash": "^4.17.21"
},
"devDependencies": {
"jest": "^29.7.0",
"eslint": "^8.55.0",
"webpack": "^5.89.0"
},
"keywords": ["javascript", "nodejs"],
"author": "Your Name",
"license": "MIT"
}
# setup.py (Python)
from setuptools import setup, find_packages
setup(
name="my-project",
version="1.0.0",
description="A sample Python project",
author="Your Name",
author_email="[email protected]",
packages=find_packages(),
install_requires=[
"flask>=2.3.0",
"requests>=2.31.0",
"pandas>=2.1.0",
],
extras_require={
"dev": [
"pytest>=7.4.0",
"black>=23.0.0",
"flake8>=6.0.0",
],
},
python_requires=">=3.8",
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
],
)
# requirements.txt
flask>=2.3.0
requests>=2.31.0
pandas>=2.1.0
# requirements-dev.txt
-r requirements.txt
pytest>=7.4.0
black>=23.0.0
flake8>=6.0.0

5. 實際項目示例

5.1 創建一個簡單的計算器包

讓我們創建一個完整的計算器包,展示模塊系統的實際應用。

正在載入編輯器...

5.2 使用計算器包

正在載入編輯器...

6. 高級模塊特性

6.1 相對導入

Python 支持相對導入,類似於 JavaScript 中的相對路徑導入。

正在載入編輯器...

6.2 動態導入

Python 支持動態導入模塊,類似於 JavaScript 的動態 import()。

正在載入編輯器...

6.3 循環導入陷阱 (Circular Imports)

循環導入是指兩個或多個模塊相互導入對方,形成一個閉環。這在 Python 中會導致 ImportErrorAttributeError,因為模塊在導入時會執行頂層代碼。

問題示例

# a.py
from b import func_b
def func_a():
func_b()
# b.py
from a import func_a
def func_b():
func_a()

解決方案

  1. 重構代碼:將共享的依賴提取到第三個模塊(推薦)。
  2. 延遲導入:將導入語句移到函數/方法內部(僅在需要時導入)。
# b.py (修復後)
def func_b():
# 延遲導入,打破循環
from a import func_a
func_a()

7. 練習題

練習 1:創建工具包

創建一個包含數學工具和字符串工具的工具包。

正在載入編輯器...

練習 2:模塊導入練習

正在載入編輯器...

8. 總結

關鍵概念回顧

  1. 模塊:任何 .py 文件都可以作為模塊使用
  2. :包含 __init__.py 的目錄,可以包含多個模塊
  3. 導入方式importfrom ... importas 重命名
  4. 特殊變量__name____file____all__
  5. 項目組織:合理的目錄結構和依賴管理

JavaScript vs Python 對比總結

概念JavaScriptPython說明
模塊文件.js 文件.py 文件都是單個文件作為模塊
目錄 + package.json目錄 + __init__.pyPython 需要 __init__.py
導入語法import { func }from module import func語法不同但概念相同
默認導出export default無對應概念Python 沒有默認導出
相對導入../utils/math..utils.math_utils都支持相對路徑
動態導入import()importlib.import_module()都支持運行時導入

下一步學習

在下一個模塊中,我們將學習:

  • 面向對象編程(類、繼承、多態)
  • 函數式編程特性
  • 裝飾器和元編程
  • 特殊方法(魔術方法)

這些概念將幫助你更深入地理解 Python 的編程範式,並能夠編寫更復雜和優雅的代碼。