Appearance
模块与包
模块和包是 Python 组织代码的基本方式。
模块基础
什么是模块
一个 .py 文件就是一个模块,模块可以包含函数、类、变量等。
python
# mymodule.py
"""这是一个示例模块"""
PI = 3.14159
def greet(name):
"""问候函数"""
return f"Hello, {name}!"
class Person:
"""人员类"""
def __init__(self, name):
self.name = name
if __name__ == "__main__":
# 模块作为脚本运行时执行
print(greet("World"))导入模块
python
# 导入整个模块
import math
print(math.pi)
print(math.sqrt(16))
# 导入模块并起别名
import numpy as np
import pandas as pd
# 导入特定内容
from math import pi, sqrt
print(pi)
print(sqrt(16))
# 导入并起别名
from math import sqrt as square_root
# 导入所有内容(不推荐)
from math import *
print(pi)
print(sin(0))
# 导入模块中的类
from mymodule import Person
p = Person("张三")模块搜索路径
python
import sys
# 模块搜索路径
print(sys.path)
# 添加搜索路径
sys.path.append("/path/to/module")
# 查看模块位置
import math
print(math.__file__)模块属性
python
import mymodule
# 模块名
print(mymodule.__name__)
# 模块文档
print(mymodule.__doc__)
# 模块文件路径
print(mymodule.__file__)
# 模块的所有属性
print(dir(mymodule))
# 模块的包名
print(mymodule.__package__)__name__ 变量
python
# mymodule.py
def main():
print("主程序")
if __name__ == "__main__":
# 直接运行模块时执行
main()
else:
# 被导入时不执行
pass
# 运行方式:
# python mymodule.py -> __name__ == "__main__"
# import mymodule -> __name__ == "mymodule"包
什么是包
包是包含 __init__.py 文件的目录,用于组织模块。
mypackage/
├── __init__.py
├── module1.py
├── module2.py
└── subpackage/
├── __init__.py
└── module3.py创建包
python
# mypackage/__init__.py
"""我的包"""
__version__ = "1.0.0"
# 导入子模块
from .module1 import func1
from .module2 import func2
# mypackage/module1.py
def func1():
return "Function 1"
# mypackage/module2.py
def func2():
return "Function 2"导入包
python
# 导入包
import mypackage
# 导入包中的模块
import mypackage.module1
mypackage.module1.func1()
# 导入包中的模块
from mypackage import module1
module1.func1()
# 导入包中的函数
from mypackage.module1 import func1
func1()
# 导入子包
from mypackage.subpackage import module3
# 导入包中所有模块(需要在 __init__.py 中定义 __all__)
from mypackage import *__init__.py 文件
python
# mypackage/__init__.py
# 包初始化代码
print("包被导入")
# 定义 __all__ 控制 from package import *
__all__ = ["module1", "module2"]
# 导入常用内容
from .module1 import func1
from .module2 import func2
# 定义包级别变量
__version__ = "1.0.0"
__author__ = "Your Name"相对导入和绝对导入
python
# 绝对导入(推荐)
from mypackage.module1 import func1
from mypackage.subpackage.module3 import func3
# 相对导入(在包内部使用)
# . 当前目录
# .. 上级目录
# ... 上上级目录
# module1.py 中
from .module2 import func2 # 同级模块
from .subpackage.module3 import func3 # 子包模块
# subpackage/module3.py 中
from ..module1 import func1 # 上级模块
from .. import module2 # 上级包的模块模块高级特性
模块重载
python
import importlib
import mymodule
# 重载模块
importlib.reload(mymodule)动态导入
python
import importlib
# 动态导入模块
module_name = "math"
module = importlib.import_module(module_name)
print(module.pi)
# 动态导入子模块
submodule = importlib.import_module("mypackage.module1")模块作为命名空间
python
# config.py
DATABASE = {
"host": "localhost",
"port": 3306,
"name": "mydb"
}
DEBUG = True
# main.py
import config
print(config.DATABASE["host"])
config.DEBUG = False标准库模块
os 模块
python
import os
# 环境变量
print(os.environ.get("HOME"))
os.environ["MY_VAR"] = "value"
# 目录操作
os.getcwd() # 当前目录
os.chdir("/path") # 改变目录
os.mkdir("dir") # 创建目录
os.makedirs("a/b/c") # 创建多级目录
# 文件操作
os.remove("file.txt") # 删除文件
os.rename("old", "new") # 重命名
# 路径操作
os.path.exists("file.txt")
os.path.isfile("file.txt")
os.path.isdir("dir")
os.path.join("a", "b", "c")sys 模块
python
import sys
# 命令行参数
print(sys.argv) # 脚本名和参数列表
# 模块搜索路径
print(sys.path)
# Python 版本
print(sys.version)
print(sys.version_info)
# 平台信息
print(sys.platform)
# 标准输入输出
sys.stdout.write("Hello\n")
sys.stderr.write("Error\n")
# 退出程序
# sys.exit(0)pathlib 模块
python
from pathlib import Path
# 创建路径对象
p = Path(".")
p = Path("D:/projects")
# 路径操作
p / "subdir" / "file.txt"
p.parent
p.name
p.suffix
p.stem
# 文件操作
p.exists()
p.is_file()
p.is_dir()
p.mkdir(parents=True, exist_ok=True)
p.touch() # 创建文件
p.unlink() # 删除文件
# 读写文件
p.read_text(encoding="utf-8")
p.write_text("content", encoding="utf-8")
# 遍历
list(p.iterdir())
list(p.glob("*.py"))
list(p.rglob("*.py"))datetime 模块
python
from datetime import datetime, date, time, timedelta
# 当前时间
now = datetime.now()
today = date.today()
# 创建日期时间
d = date(2024, 1, 15)
t = time(10, 30, 45)
dt = datetime(2024, 1, 15, 10, 30, 45)
# 格式化
print(now.strftime("%Y-%m-%d %H:%M:%S"))
print(now.isoformat())
# 解析
dt = datetime.strptime("2024-01-15", "%Y-%m-%d")
# 时间运算
tomorrow = today + timedelta(days=1)
next_week = today + timedelta(weeks=1)
# 时间差
delta = datetime(2024, 12, 31) - datetime.now()
print(delta.days)json 模块
python
import json
# 编码
data = {"name": "张三", "age": 25}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
# 解码
parsed = json.loads(json_str)
# 文件操作
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
with open("data.json", "r", encoding="utf-8") as f:
loaded = json.load(f)random 模块
python
import random
# 随机数
random.random() # 0-1 随机浮点数
random.randint(1, 100) # 1-100 随机整数
random.uniform(1, 10) # 1-10 随机浮点数
# 随机选择
items = ["a", "b", "c", "d"]
random.choice(items) # 随机选一个
random.choices(items, k=3) # 随机选多个(可重复)
random.sample(items, 2) # 随机选多个(不重复)
# 打乱顺序
random.shuffle(items)
# 随机种子
random.seed(42) # 设置种子,结果可复现collections 模块
python
from collections import Counter, defaultdict, OrderedDict, namedtuple, deque
# Counter - 计数器
c = Counter("hello world")
print(c.most_common(2)) # [('l', 3), ('o', 2)]
# defaultdict - 默认字典
d = defaultdict(list)
d["key"].append("value")
# OrderedDict - 有序字典
od = OrderedDict()
od["a"] = 1
od["b"] = 2
# namedtuple - 命名元组
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p.x, p.y)
# deque - 双端队列
dq = deque([1, 2, 3])
dq.appendleft(0)
dq.pop()itertools 模块
python
import itertools
# 无限迭代器
itertools.count(0, 2) # 0, 2, 4, 6, ...
itertools.cycle("ABC") # A, B, C, A, B, C, ...
itertools.repeat(10, 3) # 10, 10, 10
# 排列组合
list(itertools.permutations([1, 2, 3], 2)) # 排列
list(itertools.combinations([1, 2, 3], 2)) # 组合
list(itertools.product([1, 2], [3, 4])) # 笛卡尔积
# 链式操作
list(itertools.chain([1, 2], [3, 4])) # [1, 2, 3, 4]
list(itertools.islice(range(10), 2, 7)) # [2, 3, 4, 5, 6]
# 分组
data = [("a", 1), ("a", 2), ("b", 1), ("b", 2)]
for key, group in itertools.groupby(data, lambda x: x[0]):
print(key, list(group))创建可安装的包
项目结构
mypackage/
├── setup.py
├── README.md
├── requirements.txt
├── mypackage/
│ ├── __init__.py
│ ├── module1.py
│ └── module2.py
└── tests/
├── __init__.py
└── test_module1.pysetup.py
python
from setuptools import setup, find_packages
setup(
name="mypackage",
version="1.0.0",
author="Your Name",
author_email="your@email.com",
description="A sample package",
long_description=open("README.md").read(),
url="https://github.com/yourname/mypackage",
packages=find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires=">=3.6",
install_requires=[
"requests>=2.25.0",
],
)安装包
bash
# 开发模式安装
pip install -e .
# 正常安装
pip install .
# 上传到 PyPI
python setup.py sdist upload实践示例
配置管理模块
python
# config.py
"""配置管理模块"""
import json
from pathlib import Path
from typing import Any, Dict
class Config:
"""配置管理类"""
_instance = None
_config = {}
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def load(self, config_file: str):
"""加载配置文件"""
path = Path(config_file)
if path.exists():
with open(path, "r", encoding="utf-8") as f:
self._config = json.load(f)
def get(self, key: str, default: Any = None) -> Any:
"""获取配置值"""
keys = key.split(".")
value = self._config
for k in keys:
if isinstance(value, dict):
value = value.get(k)
else:
return default
return value if value is not None else default
def set(self, key: str, value: Any):
"""设置配置值"""
keys = key.split(".")
config = self._config
for k in keys[:-1]:
config = config.setdefault(k, {})
config[keys[-1]] = value
def save(self, config_file: str):
"""保存配置文件"""
with open(config_file, "w", encoding="utf-8") as f:
json.dump(self._config, f, indent=2, ensure_ascii=False)
# 使用
config = Config()
config.load("config.json")
print(config.get("database.host"))
config.set("app.debug", True)
config.save("config.json")插件系统
python
# plugins/__init__.py
"""插件系统"""
import importlib
from pathlib import Path
from typing import Dict, Type
class PluginBase:
"""插件基类"""
name = "base"
def execute(self, *args, **kwargs):
"""执行插件"""
raise NotImplementedError
class PluginManager:
"""插件管理器"""
def __init__(self):
self._plugins: Dict[str, Type[PluginBase]] = {}
def register(self, plugin_class: Type[PluginBase]):
"""注册插件"""
self._plugins[plugin_class.name] = plugin_class
def load_from_directory(self, directory: str):
"""从目录加载插件"""
plugin_dir = Path(directory)
for file_path in plugin_dir.glob("*.py"):
if file_path.name.startswith("_"):
continue
module_name = file_path.stem
spec = importlib.util.spec_from_file_location(
f"plugins.{module_name}", file_path
)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
for attr_name in dir(module):
attr = getattr(module, attr_name)
if (isinstance(attr, type) and
issubclass(attr, PluginBase) and
attr != PluginBase):
self.register(attr)
def get_plugin(self, name: str) -> PluginBase:
"""获取插件实例"""
plugin_class = self._plugins.get(name)
if plugin_class:
return plugin_class()
raise ValueError(f"Plugin not found: {name}")
def execute(self, name: str, *args, **kwargs):
"""执行插件"""
plugin = self.get_plugin(name)
return plugin.execute(*args, **kwargs)
# 使用
manager = PluginManager()
manager.load_from_directory("plugins")
result = manager.execute("my_plugin", data="test")