Python 套件 (Packages)
套件是一種組織模組的方式,將相關的模組放在同一個目錄下。套件讓大型專案的程式碼更有結構。
什麼是套件
套件就是一個包含 __init__.py 檔案的目錄。
my_package/
__init__.py
module1.py
module2.py
建立套件
目錄結構
my_project/
main.py
my_package/
__init__.py
greetings.py
math_utils.py
模組內容
# my_package/greetings.py
def say_hello(name):
return f"Hello, {name}!"
def say_goodbye(name):
return f"Goodbye, {name}!"
# my_package/math_utils.py
def add(a, b):
return a + b
def multiply(a, b):
return a * b
__init__.py
__init__.py 可以是空檔案,或者用來設定套件的公開介面:
# my_package/__init__.py
from .greetings import say_hello, say_goodbye
from .math_utils import add, multiply
__all__ = ['say_hello', 'say_goodbye', 'add', 'multiply']
匯入套件
# 方法 1:匯入整個套件
import my_package
print(my_package.say_hello("Alice"))
# 方法 2:匯入特定模組
from my_package import greetings
print(greetings.say_hello("Alice"))
# 方法 3:匯入特定函數
from my_package.greetings import say_hello
print(say_hello("Alice"))
# 方法 4:匯入 __init__.py 中定義的名稱
from my_package import say_hello, add
print(say_hello("Alice"))
print(add(3, 5))
子套件
套件可以包含子套件:
my_package/
__init__.py
core/
__init__.py
base.py
utils.py
models/
__init__.py
user.py
product.py
# 匯入子套件的模組
from my_package.core import utils
from my_package.models.user import User
相對匯入和絕對匯入
絕對匯入
使用完整的套件路徑:
# my_package/core/utils.py
from my_package.models.user import User
相對匯入
使用 . 表示相對位置:
# my_package/core/utils.py
from ..models.user import User # .. 表示上一層
from .base import BaseClass # . 表示同一層
| 語法 | 意義 |
|---|---|
. | 同一層目錄 |
.. | 上一層目錄 |
... | 上兩層目錄 |
相對匯入只能在套件內部使用,不能在直接執行的腳本中使用。
__all__ 變數
__all__ 定義了 from package import * 時會匯入的名稱:
# my_package/__init__.py
__all__ = ['say_hello', 'say_goodbye']
from .greetings import say_hello, say_goodbye
from .math_utils import add, multiply # add 和 multiply 不在 __all__ 中
from my_package import *
say_hello("Alice") # OK
# add(3, 5) # NameError: 沒有匯入
套件的命名空間
# 查看套件的內容
import my_package
print(dir(my_package))
# 查看套件的檔案位置
print(my_package.__file__)
# 查看套件的名稱
print(my_package.__name__)
實際專案結構
簡單專案
my_project/
main.py
utils.py
config.py
中型專案
my_project/
main.py
requirements.txt
src/
__init__.py
core/
__init__.py
engine.py
models/
__init__.py
user.py
utils/
__init__.py
helpers.py
tests/
__init__.py
test_core.py
test_models.py
完整專案
my_project/
README.md
setup.py
requirements.txt
.gitignore
src/
my_package/
__init__.py
core/
models/
utils/
tests/
docs/
examples/
建立可安裝的套件
setup.py
from setuptools import setup, find_packages
setup(
name="my_package",
version="0.1.0",
packages=find_packages(where="src"),
package_dir={"": "src"},
install_requires=[
"requests>=2.25.0",
],
python_requires=">=3.8",
)
pyproject.toml(現代方式)
[build-system]
requires = ["setuptools>=45", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "my_package"
version = "0.1.0"
description = "My awesome package"
requires-python = ">=3.8"
dependencies = [
"requests>=2.25.0",
]
[tool.setuptools.packages.find]
where = ["src"]
範例:建立實用套件
string_utils/
__init__.py
validators.py
formatters.py
converters.py
# string_utils/validators.py
import re
def is_email(text):
pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
return bool(re.match(pattern, text))
def is_url(text):
pattern = r'^https?://[\w\.-]+\.\w+'
return bool(re.match(pattern, text))
# string_utils/formatters.py
def to_title_case(text):
return text.title()
def to_snake_case(text):
import re
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', text)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
def to_camel_case(text):
components = text.split('_')
return components[0] + ''.join(x.title() for x in components[1:])
# string_utils/__init__.py
from .validators import is_email, is_url
from .formatters import to_title_case, to_snake_case, to_camel_case
__all__ = [
'is_email', 'is_url',
'to_title_case', 'to_snake_case', 'to_camel_case'
]
# 使用套件
from string_utils import is_email, to_snake_case
print(is_email("test@example.com")) # True
print(to_snake_case("HelloWorld")) # hello_world