Python 学习笔记
Python 学习笔记
第 1 章 Python 入门与基础
1.1 Python 简介
- 发明者:吉多・范罗苏姆(龟叔),1989 年发明,1991 年发布
- 特点:简洁易读、开源、跨平台、胶水语言,支持面向对象 / 过程 / 函数式编程
- 应用:AI、Web 开发、自动化、数据分析、爬虫、游戏、桌面软件
- 版本:Python3 为主流,不兼容 Python2
1.2 环境与开发工具
运行环境:安装 Python 时勾选Add Python to PATH
开发工具(IDE):
- PyCharm:功能全,适合专业开发,内存占用高
- VSCode:轻量免费,需装 Python 插件
- IDLE:Python 自带,适合新手
虚拟环境:隔离项目依赖,避免版本冲突,实操命令:
# 创建虚拟环境(Python3.6+) python -m venv myenv # Windows/Linux/Mac通用 # 激活虚拟环境 # Windows(cmd):myenv\Scripts\activate.bat # Windows(PowerShell):myenv\Scripts\Activate.ps1 # Linux/Mac:source myenv/bin/activate # 退出虚拟环境 deactivate
1.3 基础语法
缩进:强制用 4 个空格缩进,不用大括号
{}注释:单行
#,多行'''或"""大小写敏感,符号全为英文符号
交互模式:输入
python进入,quit()退出⚠️ 常见语法坑:
- 混淆
=(赋值)和==(比较) - 缩进不一致导致
IndentationError - 中文符号(如中文逗号、括号)触发
SyntaxError
- 混淆
第 2 章 编程核心概念
2.1 对象与引用
一切皆对象:Python 中所有东西都是对象,但变量不是对象,是指向对象的引用
对象组成:标识(id,内存地址)、类型(type)、值(value)
引用:变量存储对象地址,指向堆内存中的对象
不可变对象:int、str、tuple、bool,修改则创建新对象
- 哈希性:可哈希(hashable),可作为字典的键、集合的元素(哈希表底层依赖哈希值)
可变对象:list、dict、set,可直接修改原对象
- 哈希性:不可哈希(unhashable),不能作为字典的键、集合的元素(修改后哈希值会变,破坏哈希表结构)
⚠️ 元组特殊点:元组本身不可变,但内部可变子对象(如列表)可修改:
t = (1, [2,3]) t[1].append(4) # 执行后 t = (1, [2,3,4])哈希性核心规则:
可哈希对象:必须满足「不可变 + 有
__hash__方法」,如 int/str/tuple(无可变子对象)不可哈希对象:可变对象(list/dict/set)或重写了
__hash__为 None 的对象# 可哈希(合法) d1 = {1: "数字", "name": "字符串", (1,2): "元组"} s1 = {1, "a", (1,2)} # 不可哈希(报错 TypeError: unhashable type) d2 = {[1,2]: "列表"} # 列表不可哈希 s2 = {{1:2}: "字典"} # 字典不可哈希
2.2 标识符与变量
- 命名规则:字母 / 下划线开头,区分大小写,不能用关键字
- 命名规范:
- 类名:大驼峰(Student、MyClass)
- 变量 / 函数 / 模块:小写 + 下划线(name、say_hello)
- 常量:全大写(MAX_SPEED)
- 变量赋值:动态类型,无需声明类型,
a = 10
2.3 数据类型
2.3.1 基本类型
- int:整数,无大小限制,支持二进制 / 八进制 / 十六进制
- float:浮点数,科学计数法表示
- bool:True(1)、False(0)
- str:字符串,不可变,Unicode 编码
2.3.2 序列类型
- list:列表,可变有序序列,
[1,2,3] - tuple:元组,不可变有序序列,
(1,2,3) - dict:字典,无序键值对,键必须不可变,
{"name":"张三"} - set:集合,无序无重复元素,基于字典实现,
{1,2,3}
2.4 运算符
算术:
+ - * / // % **比较:
> < >= <= == !=,可连用(3<a<10)身份:
is/is not(比较地址),==(比较值)成员:
in/not in(判断是否在序列中)逻辑:
and or not位运算:
& | ^ ~ << >>概念 区别 示例 isvs==is比较内存地址,==比较值a=10;b=10 → a is b (True);a=[1];b=[1] → a is b (False)isinstance VS type type不推荐,无法识别子类 isinstance(10, int)(推荐);type(10) == int(不推荐,无法识别子类)
第 3 章 字符串
3.1 定义与特点
- 单 / 双 / 三引号创建,三引号支持多行
- 不可变对象,不能直接修改原字符串
- 转义字符:
\n换行、\t制表符、\\反斜杠
3.2 常用操作
- 索引 / 切片:
s[0]、s[1:5]、s[::-1](反转) - 拼接:
+(新建对象)、join()(高效) - 替换:
replace()(生成新字符串) - 分割 / 合并:
split()、join() - 查找:
find()、count()、startswith()、endswith() - 大小写:
upper()、lower()、title() - 去空格:
strip()、lstrip()、rstrip() - 格式化:
format()、f-string(f"{name}{age}") - 可指定删除字符: strip()
3.3 可变字符串
- 用
io.StringIO实现原地修改字符串
3.4 正则表达式
3.4.1 核心概念
- 作用:匹配、查找、替换、分割字符串
- 模块:
re
3.4.2 常用函数
match:从头匹配,成功返回对象search:全局搜索第一个匹配项findall:返回所有匹配结果列表sub/subn:替换字符串split:分割字符串
3.4.3 匹配规则
- 字符:
.任意字符、\d数字、\w字母数字下划线、\s空白 - 限定符:
*0+、+1+、?0/1、{m,n}指定次数 - 边界:
^开头、$结尾、\b单词边界 - 分组:
()分组,\num引用分组,(?P<name>)命名分组 - 原生字符串:
r"",解决转义冲突
第 4 章 序列(列表、元组、字典、集合)
4.1 列表 list
创建:
[]、list()、range()、推导式增:
append()(尾部)、extend()、insert()删:
del、pop()(删指定索引)、remove()(删指定值)查:索引、
index()、count()、切片改:直接赋值
lst[0] = 10排序:
sort()(原地)、sorted()(新列表)、reverse()概念 区别 示例 sort()vssorted()sort()原地排序(无返回),sorted()返回新列表lst=[3,1,2]; lst.sort() → lst=[1,2,3];sorted(lst) → 新列表,原 lst 不变append() vsextend()lst=[1,2]; lst.append([3,4]) → [1,2,[3,4]];lst.extend([3,4]) → [1,2,3,4]del vspop()vsremove()del按索引删(无返回)、pop()按索引删(有返回)、remove()按值删(无返回)
4.2 元组 tuple
- 不可变列表,无增删改方法
- 创建:
()、tuple(),单元素必须加逗号(1,) - 适用:固定数据、函数返回值、字典键
4.3 字典 dict
- 键值对存储,键唯一且不可变
- 创建:
{}、dict()、zip() - 增改:
d[key] = value、update() - 删:
del、pop()、clear() - 查:
d[key]、get()(安全)、keys()、values()、items() - 底层:哈希表(散列表),空间换时间,查询极快
4.4 集合 set
- 无序、无重复元素,自动去重
- 操作:交集
&、并集|、差集- - 增:
add()、删:remove()
第 5 章 控制语句
5.1 选择结构
- 单分支:
if 条件: - 双分支:
if-else - 多分支:
if-elif-else - 三元运算符:
值1 if 条件 else 值2 - 条件为 False:0、0.0、None、空序列、空字典
5.2 循环结构
- while:
while 条件:,适合未知次数循环 - for:遍历可迭代对象,
for 变量 in 可迭代对象: - range:
range(start,end,step),生成整数序列 - break:结束整个循环;continue:结束本次循环
- else:循环正常结束(未被 break)时执行
5.3 推导式
- 列表:
[x for x in range(10) if x%2==0]# 运行结果:[0,2,4,6,8] - 字典:
{k:v for k,v in zip(list1,list2)} - 集合:
{x for x in range(10)} - 生成器:
(x for x in range(10)),一次性迭代
第 6 章 函数
6.1 定义与调用
- 语法:
def 函数名(参数):,函数是对象 - 作用:代码复用、模块化
- 返回值:
return结束函数并返回值,无 return 返回 None
6.2 参数类型
- 位置参数:按顺序传递
- 默认参数:
def func(a,b=10),必选参数在前 - 可变参数:
*args:接收多个位置参数,打包成元组**kwargs:接收多个关键字参数,打包成字典
- 命名参数:调用时指定参数名
func(b=20,a=10) - 强制命名参数:可变参数后的参数必须命名
6.3 作用域
- 局部变量:函数内,访问快,优先级高
- 全局变量:函数外,需用
global声明修改 - nonlocal:嵌套函数中声明外层局部变量
6.4 高级特性
- lambda 匿名函数:
lambda a,b:a+b,简洁单行函数 - eval:执行字符串表达式,慎用(安全风险)
- 递归:自己调用自己,必须有终止条件
- 嵌套函数:函数内定义函数,封装数据
- LEGB 规则:局部→嵌套→全局→内建
- 「Local(函数内)→ Enclosing(嵌套函数外层)→ Global(模块级)→ Built-in(Python 内置),按这个顺序找变量,找到即停」;
6.5 参数传递
- 引用传递:全是对象引用
- 可变对象:函数内修改影响原对象
- 不可变对象:函数内修改创建新对象,不影响原对象
- 浅拷贝:拷贝对象,不拷贝子对象
- 深拷贝:
copy.deepcopy(),递归拷贝所有子对象 - ✅ 核心结论:
- 赋值
a = b:只是贴标签,共用一个对象 - 浅拷贝
copy():只拷贝第一层 - 深拷贝
deepcopy():完全独立,递归拷贝所有子对象 - 不可变对象(str/int/tuple)怎么拷贝都一样
- 可变对象(list/dict)必须用深拷贝才安全(列表套列表、字典套列表必用)
- 赋值
- ⚠️ 全局变量修改:函数内部只能读全局变量,修改必须加
global;嵌套函数改外层变量用nonlocal - 闭包:内部函数 + 引用外部环境变量 → 可保存状态(装饰器基础)
6.6 常用内置函数
| 函数名 | 用途 | 示例 |
|---|---|---|
len() |
计算长度 | len([1,2,3]) → 3 |
enumerate() |
遍历带索引 | for idx, val in enumerate(["a","b"]): print(idx, val) |
zip() |
多序列打包 | list(zip([1,2], ["a","b"])) → [(1,"a"), (2,"b")] |
sorted() |
通用排序 | sorted({"b":2, "a":1}.items(), key=lambda x:x[0]) → [("a",1), ("b",2)] |
map() |
批量处理 | list(map(lambda x:x*2, [1,2])) → [2,4] |
filter() |
过滤元素 | list(filter(lambda x:x>0, [-1,0,1])) → [1] |
第 7 章 面向对象(OOP)
7.1 核心思想
- 面向过程:执行者思维,步骤化,适合简单问题
- 面向对象:设计者思维,封装数据与行为,适合复杂协作
- 三大特征:封装、继承、多态
7.2 类与对象
- 类:模板,
class 类名: - 对象:类的实例,
对象 = 类名() - 组成:属性(数据)、方法(行为)
7.3 构造与初始化
__init__:初始化方法,初始化对象,第一个参数self__new__:创建对象,系统自动调用self:代表当前实例对象,必须为第一个参数- ⚠️ 核心区别:
__init__不是构造函数,__new__才是(__new__创建对象,__init__初始化属性)
7.4 属性与方法
实例属性:
self.属性,属于对象,互不共享类属性:
类名.属性,所有对象共享⚠️ 类属性坑:类变量不要用可变对象(如列表),否则所有实例共享导致数据污染:
class A: lst = [] # 危险!所有实例共享该列表实例方法:
def 方法(self),调用:对象.方法()类方法:
@classmethod,第一个参数cls,调用:类名.方法()静态方法:
@staticmethod,无默认参数,调用:类名.方法()
7.5 封装
- 私有成员:双下划线开头
__属性/__方法,约定私有 - 外部访问:
对象._类名__私有成员(非严格私有) - ⚠️ Python 无真正私有,仅靠约定
@property:将方法转为属性调用,实现 getter/setter
7.6 继承
- 语法:
class 子类(父类) - 作用:代码复用,扩展父类功能
- 方法重写:子类重新定义父类方法
- 调用父类:
super().方法()、父类名.方法(self) - 多重继承:支持多父类,MRO 从左到右查找方法(用
类名.mro()查看顺序,不要猜)- 「方法解析顺序,解决多继承时的方法查找冲突,比如 class A (B,C): … 用 A.mro () 看查找顺序,不要凭直觉」
- 根类:
object,所有类默认继承
7.7 多态
- 同一方法,不同对象表现不同行为
- 条件:继承、方法重写
- 特点:方法多态,属性无多态
7.8 特殊方法
__str__:打印对象时调用,自定义输出__del__:析构方法,对象销毁时调用__call__:让对象可像函数一样调用- 运算符重载:
__add__(+)、__len__(len) 等
7.9 设计模式(极简示例列举)
- 工厂模式:统一创建对象,解耦创建与调用
- 单例模式:一个类仅一个实例,重写
__new__实现 - 简单工厂模式:通过函数统一创建不同子类实例
- 适配器模式:适配不同接口,让不兼容的接口可协同工作
第 8 章 模块与包
8.1 模块
一个
.py文件就是一个模块作用:分类存放代码、避免重名、方便复用
导入方式:
import 模块名 from 模块名 import 函数/类 from 模块名 import *
8.2 包(Package)
包含
__init__.py的文件夹就是包作用:管理多个模块
导入:from 包名 import 模块名
第 9 章 异常机制
9.1 异常是什么
程序出错时会抛出异常,不处理就崩溃。
9.2 异常处理结构
try:
可能出错的代码
except 异常类型:
出错后执行
else:
不出错才执行
finally:
无论如何都执行
9.3 常见异常
SyntaxError语法错误IndexError索引越界KeyError字典键不存在AttributeError属性不存在ZeroDivisionError除 0FileNotFoundError文件不存在
9.4 主动抛异常
# 异常链(Python3.11+ 新特性)
try:
1/0
except ZeroDivisionError as e:
raise ValueError("数值错误") from e # 保留原异常栈
9.5 自定义异常
class MyError(Exception):
pass
raise MyError("自定义异常信息")
9.6 实战最佳实践
import logging
# 配置日志
logging.basicConfig(level=logging.ERROR, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
try:
1/0
except ZeroDivisionError as e:
# 记录异常(包含堆栈信息)
logging.exception("除零错误发生")
finally:
# 释放资源(文件、锁、网络连接等)
print("资源已释放")
⚠️ 注意事项:
- 不要裸
except:(会捕获KeyboardInterrupt,导致程序无法终止) - 异常捕获尽量精确,避免随便捕获
Exception
- 不要裸
第 10 章 装饰器
10.1 作用
在不修改原函数代码的前提下,给函数增加功能。
10.2 本质
把函数当作参数,返回一个新函数。
10.3 基础写法
def 装饰器(func):
def wrapper():
# 执行前逻辑
func()
# 执行后逻辑
return wrapper
@装饰器
def f():
pass
10.4 带参数、带返回值
def deco(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
return wrapper
10.5 标准万能装饰器
import functools
def 装饰器(func):
@functools.wraps(func) # 保留原函数__name__/__doc__,必加!
def wrapper(*args, **kwargs):
# 执行前逻辑(如日志、计时、权限校验)
res = func(*args, **kwargs)
# 执行后逻辑
return res
return wrapper
# 示例:带参数的装饰器
def deco_with_param(param):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"装饰器参数:{param}")
res = func(*args, **kwargs)
return res
return wrapper
return decorator
@deco_with_param("test")
def demo():
print("原函数执行")
demo() # 运行结果:装饰器参数:test → 原函数执行
10.6 装饰器叠加执行顺序
def deco1(func):
def wrapper():
print("deco1 前")
func()
print("deco1 后")
return wrapper
def deco2(func):
def wrapper():
print("deco2 前")
func()
print("deco2 后")
return wrapper
@deco1
@deco2
def f():
print("原函数")
f() # 运行结果:deco1 前 → deco2 前 → 原函数 → deco2 后 → deco1 后
- 核心规则:@装饰器 1 在上、@装饰器 2 在下 → 执行顺序:装饰器 1 外层 → 装饰器 2 外层 → 原函数 → 装饰器 2 内层 → 装饰器 1 内层
10.7 带缓存的装饰器
# 带缓存的装饰器
from functools import lru_cache
@lru_cache(maxsize=128) # 缓存函数返回值,避免重复计算
def fib(n):
if n <= 2:
return 1
return fib(n-1) + fib(n-2)
10.8 常用场景
- 日志记录
- 函数计时
- 权限检查
- 参数校验
第 11 章 生成器 & 迭代器
11.1 迭代器(Iterator)
- 可以被
for遍历的对象 - 拥有
__iter__和__next__方法
11.2 生成器(Generator)
一边循环一边计算,不占大量内存,迭代器的一种。
两种写法:
# 1. 推导式 g = (x for x in range(10)) # 运行结果:生成器对象,仅迭代一次 # 2. yield 函数 def gen(): yield 1 yield 2 g = gen() print(next(g)) # 1 print(next(g)) # 2核心特点:
- 惰性计算,仅在迭代时生成数据
- 只能遍历一次,用完即空
- 适合大数据、大文件、无限序列场景
第 12 章 并发编程(线程、进程、协程)
12.1 线程
- 最小执行单位
- 共享进程资源
- 模块:
threading - 适用场景:IO 多路并发
# 线程示例(IO 密集):
import threading
import time
def download(url):
print(f"开始下载{url}")
time.sleep(2) # 模拟IO等待
print(f"完成下载{url}")
# 启动多线程
urls = ["url1", "url2", "url3"]
threads = []
for url in urls:
t = threading.Thread(target=download, args=(url,))
threads.append(t)
t.start()
# 等待所有线程完成
for t in threads:
t.join()
print("所有下载完成")
# 线程池(简化多线程代码)
from concurrent.futures import ThreadPoolExecutor
import time
def download(url):
time.sleep(2)
return f"{url} 下载完成"
with ThreadPoolExecutor(max_workers=3) as pool:
urls = ["url1", "url2", "url3"]
results = pool.map(download, urls)
for res in results:
print(res)
12.2 进程
- 独立内存空间
- 适合 CPU 密集型任务(计算、压缩、加密)
- 模块:
multiprocessing
12.3 协程
- 极轻量,用户态切换
- 适合 I/O 密集型任务(网络、文件、爬虫)
- 模块:
asyncio
# 协程示例(IO 密集):
import asyncio
async def download(url):
print(f"开始下载{url}")
await asyncio.sleep(2) # 模拟IO等待
print(f"完成下载{url}")
# 运行协程
async def main():
urls = ["url1", "url2", "url3"]
tasks = [download(url) for url in urls]
await asyncio.gather(*tasks)
asyncio.run(main())
print("所有下载完成")
12.4 选型建议
- IO 密集(网络、文件、爬虫)→ 协程
asyncio - IO 多路并发 → 线程
- CPU 密集(计算、压缩、加密)→ 进程
第 13 章 网络编程
13.1 核心基础
- 基于 TCP/IP 模型
- Socket 套接字:服务端(绑定 → 监听 → 接收)、客户端(连接 → 发送 / 接收)
13.2 常用模块
socket(原生,仅用于学习)requests(HTTP 请求,实战首选)FastAPI/Flask(网络服务开发,实战首选)
第 14 章 文件操作
14.1 打开文件
f = open("a.txt", "r", encoding="utf-8") # ⚠️必须指定 encoding="utf-8"
- 模式:
r读、w写(覆盖)、a追加、rb二进制
14.2 自动关闭
with open("xxx.txt", "r", encoding="utf-8") as f:
data = f.read()
- 优势:自动关闭文件,即使报错也不泄露文件句柄
14.3 读写方法
read():读取全部内容(小文件)readline():逐行读取readlines():读取所有行到列表write():写入内容
14.4 示例
大文件读取:
# 逐行读取,不加载整个文件到内存
with open("big_file.txt", "r", encoding="utf-8") as f:
for line in f:
print(line.strip())
批量读取文件夹下所有 txt 文件:
import os
from pathlib import Path
folder = Path("./data")
if not folder.exists():
folder.mkdir(parents=True) # 递归创建文件夹
for file in folder.glob("*.txt"):
with open(file, "r", encoding="utf-8") as f:
content = f.read()
print(f"文件{file.name}内容:{content[:50]}") # 只打印前50字符
JSON / CSV 文件读写:
# 补充:JSON 文件读写
import json
# 写入
data = {"name": "张三", "age": 20}
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:
data = json.load(f)
附录 : 常用内置模块速查
| 模块名 | 核心用途 | 高频函数 / 类 |
|---|---|---|
| os | 系统路径 / 文件操作 | os.path.join()、os.mkdir()、os.path.exists() |
| sys | 系统参数 / 环境 | sys.argv、sys.path、sys.exit() |
| json | JSON 解析 | json.dumps()、json.loads() |
| time | 时间处理 | time.sleep()、time.time()、time.strftime() |
| datetime | 日期时间 | datetime.datetime.now()、strftime()、strptime() |
| logging | 日志记录 | logging.basicConfig()、logging.exception() |
| copy | 拷贝对象 | copy.copy ()(浅拷贝)、copy.deepcopy ()(深拷贝) |
| pathlib | 路径处理(推荐) | Path()、Path.joinpath()、Path.exists() |
附录 :避坑清单
- 路径问题:不要写绝对路径(如
C:\xxx),用pathlib/os.path拼接路径 - 编码问题:打开文件必须指定
encoding="utf-8" - 装饰器:必须加
@functools.wraps(func),否则原函数信息丢失 - 类属性:不要用可变对象(列表 / 字典)作为类变量
- 异常处理:不裸捕
except,不随便捕获Exception - 大文件:用逐行读取,避免加载整个文件到内存
- 拷贝:嵌套可变对象必须用深拷贝
copy.deepcopy() - 生成器:生成器只能迭代一次,迭代后再次调用
next()会抛StopIteration - 字符串拼接:大量拼接用
join()而非+(+会频繁创建新对象,效率低)
