模块
示例:
# 1. 模块的文档字符串"""module1
这个模块提供的功能作者时间等元数据"""# 2. 变量 (Variables)a=1
# 3. 常量 (Constants) - Python中没有真正的常量,但约定大写表示常量PI =3.14
# 4. 函数 (Functions)def add(a,b): return a+b
# 5. 类 (Classes)class Student:
def __init__(self, name=None, age=None): self._name = name self._age = age @property#相当于get方法 def age(self): return self._age
@age.setter#set方法 def age(self, value): self._age = value
# 6.模块的主函数import sysprint(f"__name__ = {__name__}")#如果是直接运行这个模块的话,__name__就是__main__,#如果是被调用的话,__name__是这个模块的名字。if __name__ == "__main__": print("这个只有在这个模块被直接运行的时候才会执行")print(__doc__)#打印这个模块的文档字符串包
包是包含多个模块的目录,包含__init__.py文件。
project/├── package1/│ ├── __init__.py│ ├── module2.py│ └── module3.py├── package2/│ ├── __init__.py│ ├── package1/│ │ ├── __init__.py│ │ └── moudle4.py│ └── module5.py├── module1.py└── main.py#显示表示这个包里有什么模块,这两个模块会放在package1的命名空间中from . import module2from . import module3#init文件里可以写当这个包被调用时的函数,多次import这个包不会重复执行init文件里的主函数print("package1初始化文件被执行")#当然也能写包的函数,变量,常量,会进入到包的命名空间def add(a,b): return a+b#如果__init__.py里的命名和模块名重了,那么保留__init__.py里自带的,上面导入的模块将无法使用def module2(a,b):#p1.module2将不会指定到module2模块,而是这个函数 return a+b
from .module2 import add,PI
# 控制主函数 from package import * 引入的东西__all__ = ['add']#只引的进add导入
#导入整个模块,主函数命名空间dir()只有module1(模块名)被占用import module1a=module1.a# 从模块导入特定内容,主函数命名空间dir(),只有被import的命名会被占用,如果是*的话会把所有的module里的命令引入过来from module1 import a, adda=add(1,2)#如果使用了as那就只会把as后的名称进入命名空间import numpy as np#不能使用numpy只能用npimport package1.module2#package1被导入到主函数命名空间,module1被导入package1的命名空间,即使没用__init__.py也行#会被包的__all__控制from package1 import *包管理
这两个视频非常重要,算是工程应用包管理的核心一步了,不看不行。可以去底下那些库里看一下大部分开源项目的项目结构。
pip
pip list# 生成环境库的列表pip freeze > requirements.txt#把requirements.txt里的依赖全安装下来pip install -r requirements.txt但是requirements.txt混合了所有直接和间接依赖, 所以现代配置依赖以及管理项目元数据使用pyproject.toml。
[project]name = "simple-project"version = "0.1.0"description = "一个简单的Python项目"authors = [{name = "Your Name"}]dependencies = [ "requests>=2.25.0", "click>=8.0.0", ][build-system]requires = ["setuptools>=45", "wheel"]build-backend = "setuptools.build_meta"使用pip安装.toml文件中的所有依赖
pip install -e .#-e代表编辑模式可以把自己的项目作为一个依赖放在依赖路径中,调用时可以当正常依赖调用uv
#列出所有可用的python版本,freetreaded实验版本不要用。uv python list#安装pythonuv python install [可选版本]#可以直接py脚本可以是python本身,进入对应版本的python解释器。如果没装过你指定的那个版本就会自动给你安装#后面-p <python版本>可以不写,toml文件中指定了版本,他就会自动调用那个版本,没指定就用已安装的最新的。#运行时自动进入该项目的虚拟环境uv run [-p <python版本>] <py脚本>#还可以运行python本身uv run python#还可以运行ruff等工具uv tool run [已安装的工具]#初始化一个标准python项目uv init [-p <python版本>]#自动帮你修改toml文件uv add <python库>#把这个库安装到开发环境uv add --dev python-dotenv#列出所有的依赖关系uv tree#工具将安装到全局uv tool install <工具名>uv tool list#根据当前项目的toml文件自动下载全部依赖uv sync#不要开发依赖uv sync --no-dev#清除uv的下载库的缓存,有时候下不动了可以用uv cache clean常用的库
| 库名 | PIP 安装命令 | 描述 |
|---|---|---|
| opencv | uv add opencv-python | 开源计算机视觉库,用于图像处理和计算机视觉任务 |
| matplotlib | uv add matplotlib | Python 绘图库,创建静态、动态和交互式可视化 |
| numpy | uv add numpy | 科学计算基础包,提供多维数组对象和各种派生对象 |
| os | (Python 内置) | 操作系统接口模块,提供文件和目录操作功能 |
| subprocess | (Python 内置) | 用于创建和管理子进程,执行外部命令 |
| pynput | uv add pynput | 控制和监控输入设备的库,支持键盘和鼠标监听 |
| flask | uv add flask | 轻量级 Web 框架,简单灵活,适合小型项目和 API |
| django | uv add django | 高级 Web 框架,功能完整,适合大型企业级应用 |
| fastapi | uv add fastapi | 现代高性能 Web 框架,基于类型提示,自动生成 API 文档 |
| ruff | uv add ruff | 极速的 Python 代码检查器和格式化工具 |
| BeautifulSoup | pip install beautifulsoup4 | HTML 和 XML 解析库,用于网页数据抓取 |
| Pandas | uv add pandas | 数据分析库,提供高性能、易用的数据结构和分析工具 |
| PySide | uv add PySide6 | Qt 框架的 Python 绑定,用于创建桌面应用程序 |
| pathlib | (Python 内置) | 面向对象的文件系统路径操作模块 |
| IPython | uv tool install ipython | 一个功能强大的 交互式 Python 解释器 |
| jupyter | uv tool install jupyterlab | 一个基于浏览器的交互式计算环境,让你能在网页中写代码、运行代码、并立即看到结果。 |
| tkinter | (Python 内置) | python自带的ui库 |
| pillow | uv add pillow | Python 图像库 |
| Requests | uv add requests | 一个优雅且简单的 Python HTTP 库,专为人类设计。 |
| feedparser | uv add feedparser | rss解析器 |
| gunicorn | uv add gunicorn | 基于 Unix 的 Python WSGI HTTP 服务器 |
| SQLite | (Python 内置) | 轻量级数据库 |
| scapy | uv add scapy | 基于 Python 的交互式数据包作程序和库。 |
| SQLAlchemy | uv add sqlalchemy | Python SQL 实例和对象关系映射器(ORM) |
| python-dotenv | uv add python-dotenv | 从 工作目录的.env 文件读取键值对,加载到内存中,os.getenv()来取出 |
| pyjwt | uv add pyjwt | 给web项目的jwt的库 |
| Psycopg | uv add psycopg2-binary | PostgreSQL的python适配器 |
| Flask-Migrate | uv add Flask-Migrate | 处理 Flask 应用的 SQLAlchemy 数据库迁移(数据库的版本管理) |
| alembic | uv add alembic | SQLAlchemy项目下面的数据库迁移的 |
| pydantic | uv add pydantic | 类型验证 |
| taskiq | uv add taskiq | 异步分布式任务管理器 |
| pymupdf | uv add pymupdf | PDF处理库 |
| httpx | uv add httpx | 异步的http请求客户端 |
| rich | uv tool install rich | 用于向终端编写富文本(带有颜色和样式) |
| celery | uv add celery | 分布式任务队列 |
| inspect | (Python 内置) | 用于自省,太变态了,说实话 |
| contextvars | (Python 内置) | 上下文变量 |
推荐的开源项目
异常
实践
在底层实现抛出异常,在上层有能力处理什么异常就except这个异常然后进行处理。千万不要在上层直接except Exception全给排除了,这样底层抛出的一切信息全没了。一定要你这里能负责了,你再except,没法负责你就不要try,except,还不如让这个报错继续网上浮现,让再上面处理,实在不行压根就不用处理,让他走到最上层让框架或者解释器直接打印出来,千万不要看到啥就无脑except Exception,要负责的。
python库的那些异常都会抛出异常的,不需要你去再画蛇添足了,但是比如你要对接第三方的http请求,这种就需要你自己根据响应来自己构建一套这个api专用的异常来抛出了。但是具体要怎么组织项目的异常类,就八仙过海各显神通了。
raise
只能抛出一个异常类实例,当抛出一个异常之后,当前的线程的所有事情全部停下,开始一层一层的匹配except,一旦匹配到了,那么就进入那个except的块里,进行处理异常的逻辑。如果没有匹配到会浮现到最上层,
异常类
就和定义一个普通的类一样,但是定义异常类的时候必须继承于Exception。
try except
就有点像是一个全局的if,在他的范围内,一直盯着有没有raise出来,有raise出来了就看看是什么类型的exception,从而对异常进行判断和处理。
虚拟环境
创建虚拟环境
python -m venv <环境名称> #主流使用.venv他会在你的当前目录下创建一个对应名称的文件夹环境存在的地方
激活虚拟环境
# Windows<环境名称>\Scripts\activate# macOS/Linuxsource <环境名称>/bin/activate退出虚拟环境
deactivate命名规范
反正除了类用大驼峰和java一样,别的变量名,模块名,函数名全部是用蛇形(全小写,词之间用_分隔),常量使用全大写。 python约定,_单下划线开头的是私有变量,但是其实只是ide里看不到了,实际上真想调用还是可以的不是强制的,下划线的一般是魔法变量,比如__str()这个是print会调用的,转字符串的类似于toString()。
Byte
python初始化二进制字节流,感觉还是c的定义方式我喜欢一点。
a = b'\x41\x7A' # 把16进制数转化成字节流b = b'Az' #会把这种字符根据ascii码变成字节流c = bytes([0x41, 0x7A])bytearray([0x01]) #这种可以动态的调整字节流的长度,可以不断的添加print(a == b == c) # 输出: True‘和”
python里这俩是完全等价的,老是被c搞得都ptsd了。不过工程上我们最好区分一下使用场景这样更好看好看点,
| 场景 | 推荐引号 | 暗示的意义 |
|---|---|---|
| 内部标识符/Key | 'id', 'status' | “这是程序内部用的变量名,不是给人读的句子。” |
| 用户可见文本 | "上传成功" | “这是要显示在 UI 上给人看的句子。” |
| SQL / 正则表达式 | 'SELECT * FROM...' | “这是另一种语言的代码块。” |
| Docstring / 长注释 | """ ... """ | “这是属于这个函数的说明书。” |
闭包
这个我转载一篇文章写的非常不错。 我这放俩代码段,非常好理解
#这个函数直接返回了f2函数,f2的函数的域在f1里面,所以可以直接访问n,这样你就可以通过f2来访问到n变量了def f1(): n=999 def f2(): print(n) return f2
def timer(func): # 这里的 func 就相当于上面代码里的 n def wrapper(): # 这里的 wrapper 就是上面代码里的 f2 start = time.time() func() # 就像 print(n),这里我们执行了这个函数 end = time.time() print(f"执行耗时: {end - start}s") return wrapper # 返回内层函数
new_func = timer(my_task)#你把随便一个函数当成func扔进这个timer函数里,就会把他重新构建打包并返回回来,这就是装饰器的最简单的原理当你写下:
@timerdef my_task(): print("我在干活")其实就相当于把my_task=timer(my_task),把原来的函数重新通过timer打包了。
真正的装饰器:
import time
def timer(func): def wrapper(*args, **kwargs): start = time.time()
result = func(*args, **kwargs)
end = time.time() print(f"执行耗时: {end - start}s") return result return wrapper
@timerdef my_task(): time.sleep(1) print("任务完成")当你在调用my_task()的时候,这个my_task其实早已经被my_task=timer(my_task)了,这个时候的my_task其实是被处理完返回的了。这就不难理解为啥要 def wrapper(*args, **kwargs): 然后再把这个接收到的参数放到func的参数里了。
*args(Arguments):是一个元组 (Tuple)。它负责把所有按位置传进来的参数(比如1, 2, 3)打包在一起。**kwargs(Keyword Arguments):是一个字典 (Dict)。它负责把所有带名字的参数(比如a=1, b=2)打包在一起。 把所有的参数全打包起来,然后转手发给func。
这里*args和**kwargs,之所以python选择这么起名,在正则里一般*是指匹配任意数量的,args意思是匹配任意数量的参数。而**kwargs意思是匹配任意数量的键值对,如果只有一个意思是只要所有的键,可能是这样
python交互式解释器
也被叫做:(REPL)[https://docs.python.org/zh-cn/3.14/glossary.html#term-REPL]。一般来说,想要调用python解释器,有两种。一种python <模块>,另一种直接python进入python交互式解释器。
ipython
其实就是高级版的python交互式解释器,可以很快速的调试一个新库和测试模块,更好使的是他内置了一个Global Event Loop,你可以很方便的直接await一个异步函数,不需要用asyncio.run()来点火,方便极了,用了这个就再也不想用原版的了。
使用方法的话,不知道有什么有什么对象就按tab,不知道对象怎么用的话就按?,非常符合直觉,多用用很快就上手了。但是功能远不止于此啊,建议去看看人家的文档。
- F2:批量写入代码块