Python 的名字来源于吉多所喜爱的电视剧 《蒙提·派森的飞行马戏团》,而不是蟒蛇。
当在 Python 中输入 import this 会看到下面文字:
优美胜于丑陋,明确胜于隐晦,简洁胜于复杂。 ——The Zen of Python, by Tim Peters
1989 年荷兰龟叔(吉多)打发圣诞假期时间,决定写一门新语言
1994 年发布 1.0
2000 年发布 2.0,2020 年 1 月停止维护
2008 年发布 3.0
目录
数据类型
Python 是弱类型语言,变量不需要声明类型,变量可以随时赋值为不同类型的数据。
# 整数
age = 18
largeNumber = 1_000_000_000
# 不同进制的表示
binary = 0b1010 # 0b开头表示二进制数,等于十进制的10
hex_num = 0xFF # 0x开头表示十六进制数,等于十进制的255
# 浮点数
height = 1.75
# 科学计数法表示
light_speed = 3e8 # 光速:3 × 10^8 米/秒
atom_size = 1e-10 # 原子大小:1 × 10^-10 米
# 基本字符串
name = "小明" # 使用双引号
greeting = '你好' # 使用单引号
print(f"{name}说:{greeting}") # 输出:小明说:你好
# 使用转义字符 \ 来表示特殊字符
message = "他说:\"Python很有趣!\"" # 使用转义字符
# 三引号字符串
# 可以包含多行文本,保留所有的换行和空格
# 适合编写文档字符串、多行文本等
long_text = """这是一个多行字符串,
不需要使用特殊的转义字符。"""
# 基本布尔值
is_sunny = True # 今天天气晴朗
is_raining = False # 今天没有下雨
# 比较运算
age = 18
can_vote = age >= 18 # 判断是否达到投票年龄
print(f"可以投票吗?{can_vote}") # 输出:可以投票吗?True
# 逻辑运算
# 逻辑运算符:and、or、not
# 逻辑运算符用于组合多个条件
# and:所有条件都为True时,结果为True
# or:只要有一个条件为True,结果为True
# not:对条件取反
has_ticket = True
has_id = True
can_enter = has_ticket and has_id # 需要同时满足两个条件
print(f"可以入场吗?{can_enter}") # 输出:可以入场吗?True
# 空值的使用
student_name = None # 表示学生姓名暂时未知
print(f"学生姓名:{student_name}") # 输出:学生姓名:None
# 多个变量同时赋值
x, y, z = 1, 2, 3
print(f"x={x}, y={y}, z={z}") # 输出:x=1, y=2, z=3
# 变量的交换
a = 1
b = 2
a, b = b, a # 交换a和b的值
print(f"a={a}, b={b}") # 输出:a=2, b=1
# 使用type()函数查看变量的类型
print(type(score)) # 输出:<class 'int'>
print(type(name)) # 输出:<class 'str'>
print(type(is_passed)) # 输出:<class 'bool'>字符串
- 字符串不可变,修改字符串会生成新对象
- 中文字符串建议统一使用 UTF-8 编码
- 处理文件时要注意文件的编码格式
## 字符串和数字的拼接
# 字符串和数字拼接时,不能直接拼接,需要先将数字转换为字符串
age = 20
message = "我今年" + str(age) + "岁"
print(message) # 输出:我今年20岁
# 字符串重复
laugh = "哈" * 5 # 字符串可以和数字相乘,表示重复
print(laugh) # 输出:哈哈哈哈哈
# 字符串不可变的例子
s = "hello"
s2 = s.replace("h", "H")
print(s) # 输出:hello(原字符串没变)
print(s2) # 输出:Hello(新字符串)
# 索引
word = "Python"
print(word[0]) # 输出第一个字符:P
print(word[-1]) # 输出最后一个字符:n
# 切片
greeting = "Hello, world!"
print(greeting[0:5]) # 输出:Hello(从第0到第4个字符,不包括第5个)
print(greeting[7:]) # 输出:world!(从第7个字符到结尾)
print(greeting[:5]) # 输出:Hello(从开头到第4个字符)
# 大小写转换
text = "Python is Fun!"
print(text.lower()) # 全部转为小写:python is fun!
print(text.upper()) # 全部转为大写:PYTHON IS FUN!
# 查找和替换
sentence = "I love apples, apples are sweet."
print(sentence.find("apples")) # 查找'apples'第一次出现的位置,输出:7
print(sentence.replace("apples", "oranges")) # 替换所有'apples'为'oranges'
# 百分号格式化
name = "小红"
age = 20
# 这是Python中的百分号格式化字符串方法
# %s 是一个占位符,表示将被字符串替换
# %d 是一个占位符,表示将被整数替换
# 括号中的(name, age)是要插入到字符串中的变量
# 变量会按顺序替换占位符:name替换%s,age替换%d
print("大家好,我叫%s,今年%d岁。" % (name, age)) # %s表示字符串,%d表示整数
# 常见的格式化占位符:
# %s - 字符串
# %d - 整数
# %f - 浮点数
# %.2f - 保留两位小数的浮点数
# %% - 输出百分号本身
# format {} 占位
fruit = "香蕉"
price = 3.5
print("今天的{}价格是{}元一斤。".format(fruit, price)) # 用{}占位,后面用format填充
# f-string格式化
score = 98
student = "李雷"
print(f"{student}的考试成绩是{score}分。") # 变量名直接写在{}里
# 小明的身高和体重
height = 1.75 # 单位:米
weight = 80.5 # 单位:千克
# 计算BMI指数,公式:体重 / (身高的平方)
bmi = weight / (height ** 2)
print(f"小明的BMI指数为:{bmi:.2f}") # 保留两位小数编码与解码
# 编码为UTF-8字节
msg = "你好,世界"
msg_bytes = msg.encode("utf-8") # 编码为字节
print(msg_bytes) # 输出:b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c'
# 解码回字符串
msg_str = msg_bytes.decode("utf-8") # 解码为字符串
print(msg_str) # 输出:你好,世界
# 遍历字符串
for char in "Python":
print(char) # 依次输出每个字符
# 判断字符串内容
email = "user@example.com"
print(email.startswith("user")) # 判断是否以"user"开头,输出:True
print(email.endswith(".com")) # 判断是否以".com"结尾,输出:True
print(email.isdigit()) # 判断是否全是数字,输出:False在 Python 中,当程序执行过程中遇到错误时,会抛出异常。我们可以使用 try-except 语法来捕获并处理这些异常,避免程序崩溃。
# 错误示例:用GBK解码UTF-8字节
try:
msg = "你好,世界"
msg_bytes = msg.encode("utf-8") # 编码为字节
wrong_str = msg_bytes.decode("gbk") # 这里会报错,因为尝试用GBK解码UTF-8编码的字节
except UnicodeDecodeError as e:
# except 代码块:捕获并处理特定类型的异常
# UnicodeDecodeError 是解码错误的异常类型
# as e 将异常对象赋值给变量e,以便后续使用
print("解码出错:", e) # 打印错误信息-- 2025 年 9 月 22 日止 --
列表 list
- 列表是 Python 中常用的数据结构,可以存储多个元素,元素可以是不同的数据类型。
- 列表是可变对象,可以随时增删改查。
# 创建一个空列表
empty = []
print(len(empty)) # 输出:0
# 创建一个装水果的列表
fruits = ["苹果", "香蕉", "橙子"]
print(fruits) # 输出整个列表:['苹果', '香蕉', '橙子']
# 查看列表中有多少个元素
print(len(fruits)) # 输出:3
# 索引从0开始,依次访问每个水果
print(fruits[0]) # 输出第一个元素:苹果
print(fruits[1]) # 输出第二个元素:香蕉
# 访问最后一个元素,可以用-1
print(fruits[-1]) # 输出倒数第一个元素:橙子
# 访问不存在索引的元素会报错
# print(fruits[3]) # 报错:IndexError: list index out of range
# 在列表末尾添加一个新水果
fruits.append("葡萄")
print(fruits) # 输出:['苹果', '香蕉', '橙子', '葡萄']
# append一次只能添加一个元素
fruits.append("西瓜", "柠檬") # 报错:TypeError: append() takes exactly one argument (2 given)
# 在指定位置插入一个水果,比如插到第2个位置(索引为1)
fruits.insert(1, "西瓜")
print(fruits) # 输出:['苹果', '西瓜', '香蕉', '橙子', '葡萄']
# 删除最后一个水果
last = fruits.pop()
print(last) # 输出被删除的水果:葡萄
# 删除指定位置的水果,比如删除第2个(索引为1)
removed = fruits.pop(1)
print(removed) # 输出被删除的水果:西瓜
print(fruits) # 输出:['苹果', '香蕉', '橙子']
# 把第二个水果改成“柠檬”
fruits[1] = "柠檬"
print(fruits) # 输出:['苹果', '柠檬', '橙子']
# 创建一个嵌套列表,类似二维表格
matrix = [
[1, 2, 3],
[4, 5, 6]
]
# 访问第二行第三列的元素
print(matrix[1][2]) # 输出:6元组 tuple
- 元组不可变性
- 只有一个元素的元组要加
,逗号 - 元组可以包含可变对象
# 创建一个元组,存放三种颜色
colors = ("红色", "绿色", "蓝色")
print(colors) # 输出:('红色', '绿色', '蓝色')
# 访问元组的元素,和列表一样
print(colors[0]) # 输出:红色
print(colors[-1]) # 输出:蓝色
# 尝试修改元组的内容会报错
colors[1] = "黄色" # 这一行会报错:TypeError: 'tuple' object does not support item assignment
# 元组中的列表内容可以修改
fruits = ("苹果", ["香蕉", "橙子"])
fruits[1][0] = "西瓜"
print(fruits) # 输出:('苹果', ['西瓜', '橙子'])
# 注意:只有一个元素的元组要加逗号
single = (42,)
print(type(single)) # 输出:<class 'tuple'>
not_tuple = (42)
print(type(not_tuple)) # 输出:<class 'int'>
# 这是一个三层嵌套的列表
data = [
["Tom", "Jerry", "Spike"],
["Python", "Java", "C++"],
["Alice", "Bob", "Eve"]
]
# 取出"Tom"
print(data[0][0]) # 输出:Tom
# 取出"Java"
print(data[1][1]) # 输出:Java
# 取出"Eve"
print(data[2][2]) # 输出:Eve
# 判断变量是不是元组
a = ()
b = (1)
c = [2]
d = (3,)
e = (4, 5, 6)
print(isinstance(a, tuple)) # True,空元组
print(isinstance(b, tuple)) # False,b是整数
print(isinstance(c, tuple)) # False,c是列表
print(isinstance(d, tuple)) # True,只有一个元素的元组
print(isinstance(e, tuple)) # True,多个元素的元组if 条件判断
- 条件可以是任意表达式
if条件后面,必须由冒号elif和else都是可选分支- 判断的顺序很重要
- 空列表
[]返回False
age = 21 # 定义一个变量age,表示年龄
# 基础语法
if age >= 18: # 如果年龄大于等于18
print("你已经成年啦!") # 满足条件时执行
print("可以独立做很多事情。") # 这行也会被执行
# 如果age小于18,这两行不会被执行
# elif 用法
score = 72
if score >= 90:
print("优秀")
elif score >= 75:
print("良好")
elif score >= 60:
print("及格")
else:
print("不及格")
# 程序会从上往下判断,遇到第一个满足条件的分支就执行,然后跳过后面的分支
# 如果用户输入的不是数字,int()会报错
user_input = input("请输入一个数字:")
try:
number = int(user_input) # 尝试转换为整数
print("你输入的数字是:", number)
except ValueError:
print("输入的内容不是有效的数字,请重新输入。")
# 判断一个列表是否有内容
numbers = [1, 2, 3]
if numbers: # 非空列表会被当作True
print("列表有内容")
else:
print("列表是空的")
numbers2 = []
if numbers2: # 空列表会返回False
print("列表有内容")
else:
print("列表是空的")match
- Python 3.10 及以上版本引入了
match语句 case _:表示“其他所有情况”,相当于if语句中的else- 用
|可以同时匹配多个值 - 条件匹配
case s if ...中的s会绑定当前值,后面的if是附加条件
文字,多值,条件
# 假设我们要根据天气情况给出不同的建议
weather = "rainy"
# 使用match语句进行多分支判断
match weather:
case "sunny":
print("天气晴朗,适合出门散步。") # 如果是晴天
case "rainy":
print("下雨了,记得带伞。") # 如果是雨天
case "snowy":
print("下雪了,注意保暖。") # 如果是雪天
case _:
print("无法识别的天气类型。") # 其他情况
# 判断一个月份属于哪个季节
month = 4
match month:
case 12 | 1 | 2:# 12月、1月、2月属于冬季
print("冬季")
case 3 | 4 | 5:# 3月、4月、5月属于春季
print("春季")
case 6 | 7 | 8:# 6月、7月、8月属于夏季
print("夏季")
case 9 | 10 | 11:# 9月、10月、11月属于秋季
print("秋季")
case _:# 其他情况
print("月份无效")
# 判断分数等级
score = 85
match score:
case s if s >= 90:
print("成绩优秀")
case s if 80 <= s < 90:
print("成绩良好")
case s if 60 <= s < 80:
print("成绩及格")
case _:
print("成绩不及格")list
- 匹配
list,也能匹配大多数序列类型(如tuple、range、自定义序列) - 用
*解包剩余元素,如*rest,用于“吃掉剩余的元素” - 可以放至多一个星号目标,
[a, *mid, *mid2]会报错 - 星号目标位置不限(可在中间、开头、结尾)
- 星号目标得到的是列表(就算原序列是 tuple)
- 星号后面要跟一个名字(变量名),也可用
_代表“丢弃” []/()写法等价:都是“序列模式”,不限制具体容器类型
match seq:
case [x, y, *rest]:
return f"≥2 个元素:x={x}, y={y}, rest={rest}"
case _:
return "不匹配"
match nums:
case [x, y, *rest] if x <= y and all(n >= 0 for n in rest):
return f"非降序起步且其余非负:x={x}, y={y}, rest={rest}"
case [x, *_, z] if z % 2 == 0:
return f"以偶数 {z} 结尾"
case _:
return "其它"
# 先判断数据结构
def handle(msg):
match msg:
case {"kind": "pay", "amount": amt} if amt > 0:
return f"支付 {amt}"
case {"kind": "pay", "amount": amt} if amt <= 0:
return "金额非法"
case _:
return "未知消息"
print(handle({"kind": "pay", "amount": 100})) # 支付 100
print(handle({"kind": "pay", "amount": 0})) # 金额非法
print(handle({"kind": "pay", "amount": -5})) # 金额非法
print(handle({"kind": "refund", "amount": 50})) # 未知消息
print(handle({"foo": 1})) # 未知消息
print(handle(["pay", 100])) # 未知消息循环
for … in …
# 假设有一个学生名单
students = ["小明", "小红", "小刚"]
# 用for循环依次打印每个学生的名字
for student in students:
print(student) # 每次循环,student变量会依次等于列表中的每个名字
# 计算1到10的累加和
total = 0 # 用于累加的变量
# 使用range()函数生成1到10的整数序列
# range()函数可以生成一个整数序列,包含从开始到结束(不包含结束)的整数
# 例如,range(1, 11)会生成1到10的整数序列
# range(5) 会生成0到4的整数序列 [0, 1, 2, 3, 4]
for number in range(1, 11):
total += number # 每次循环把当前数字加到total上
print("1到10的和是:", total) # 输出:1到10的和是:55
list(range(5, 1, -1)) # [5, 4, 3, 2]
# 注意 stop 是开区间,不包含 1;想包含 1 用 range(5, 0, -1)
# for循环可用于循环字符串
for char in "Hello":
print(char)while (boolean)
# 用while循环打印1到5
n = 1
while n <= 5: # 只要n小于等于5就继续循环
print(n)
n += 1 # 每次循环n加1for … else
for i in range(2, 6):
for j in range(2, i):
if i % j == 0:
break
else:
print(i, "是素数") # 只有内层没 break 时才会打印break & continue
- break 遇到特殊情况提前结束循环
- continue 跳过本次循环,直接进入下一轮
# 打印1到100,但遇到第一个能被7整除的数就停止
for i in range(1, 101):
if i % 7 == 0: # 如果i能被7整除
print("遇到第一个能被7整除的数:", i)
break # 立即结束整个循环
print(i)
# 打印1到10中的所有奇数
for i in range(1, 11):
if i % 2 == 0: # 如果是偶数
continue # 跳过本次循环,后面的print不会执行
print(i) # 只会打印奇数
# 跳出多层的方式
for i in range(1, 4):
for j in range(1, 4):
if j == 2:
break # 只跳出内层 for j
print(f"i={i}, j={j}")
print("done")
# 标志位跳出
found = False
for i in range(1, 6):
for j in range(1, 6):
if i * j == 12:
found = True
break # 先跳出内层
if found:
break # 再根据标志位跳出外层
print("结束于:", i, j) # -> i=3, j=4
# retrun 跳出
def find_first_mul12():
for i in range(1, 6):
for j in range(1, 6):
if i * j == 12:
return i, j # 直接从函数返回,等同跳出所有层
return None
print(find_first_mul12()) # -> (3, 4)
# 抛出并捕获自定义异常
# 这种方式在需要从深层嵌套中“立即脱身”又不方便改函数结构时挺好用,但要注意可读性。
class BreakOut(Exception): pass
try:
for i in range(1, 6):
for j in range(1, 6):
if i * j == 12:
raise BreakOut((i, j))
except BreakOut as e:
i, j = e.args[0]
print("捕获到位置:", i, j)O (1) vs O (n)
在 set / dict 里用 in 查找,通常不管集合多大,耗时都近似常数;而在 list 里,集合越大,查得越慢。
- O(1):算法复杂度的“常数时间”——不随元素个数 n 线性增长。查 10 个元素和查 100 万个元素,平均都只需几步常数级操作(算哈希 → 定位槽位 → 比较少量元素)。
- 平均:指通常情况(随机分布、哈希函数表现正常)。哈希表把元素分散到不同“桶”里,冲突很少,所以一步就能定位。
- 对比:
x in some_set/x in some_dict→ 平均 O(1)x in some_list/x in some_tuple→ O(n)(最坏可能要从头扫到尾)
字典 mapping
- 一种映射(mapping):从键 key到值 value的对应关系。
- 语法:
{key: value, ...};空字典{}或dict() - 3.7+ 起保持插入顺序(遍历顺序就是插入顺序)
- 查找/新增/删除平均 O(1),靠哈希表实现
- 键必须可哈希(不可变):常用
str/int/float/tuple/frozenset;❌list/dict/set不能当键
book = {"title": "Fluent Python", "price": 88, ("pub","year"): 2021}
d = {"a": 1}
# 查
d["a"] # 1;键不存在会 KeyError
d.get("x", 0) # 0;更安全:给默认值
"x" in d # False
# 增改
d["b"] = 2
d.update({"c": 3, "a": 9}) # 批量合并/覆盖
d |= {"d": 4} # 3.9+ 合并运算
{**d, **{"e": 5}} # 解包合并成新字典
# 删
del d["b"]
d.pop("c", None) # 带默认值更稳
d.clear() # 清空
for k in d: ... # 键
for k, v in d.items(): ... # 键值对
d.keys(), d.values(), d.items() # 动态“视图”,随字典变化而变
# 构造字典的优雅方式
squares = {x: x*x for x in range(5)} # {0:0, 1:1, ...}
# 缺省值与计数的三种姿势
# 1) get
counts = {}
for ch in "banana":
counts[ch] = counts.get(ch, 0) + 1
# 2) setdefault(返回并设置缺省)
d = {}
for k, v in [("a",1),("a",2)]:
d.setdefault(k, []).append(v)
# 3) defaultdict(推荐频繁缺省场景)
from collections import defaultdict, Counter
dd = defaultdict(list)
for k, v in [("a",1),("a",2)]: dd[k].append(v)集合 set
- 集合(set)是一种无序、元素不重复的容器
- 语法:
{1, 2, 3}或set()(空集合只能用set(),{}是空字典) - 元素必须可哈希(不可变):如
int/str/tuple;❌list/dict/set不能放进set - 自动去重;成员测试
in平均 O(1) - 无序,不支持下标访问
# 集合的元素必须是不可变类型,比如数字、字符串、元组
valid_set = {1, "hello", (2, 3)}
print(valid_set) # 输出:{1, 'hello', (2, 3)}
# 不能把列表放进集合,否则会报错
wrong_set = {[1, 2, 3]} # 这一行会报TypeError: unhashable type: 'list'
# 常用操作
s = {1, 2, 3}
s.add(4) # {1,2,3,4}
s.update([3, 5, 6]) # {1,2,3,4,5,6}
s.discard(10) # 删不存在的元素也不会报错
# s.remove(10) # 不存在会 KeyError
x = s.pop() # 随机弹出一个元素(因无序)
# 集合代数
a, b = {1,2,3}, {3,4,5}
a | b # 并集 {1,2,3,4,5}
a & b # 交集 {3}
a - b # 差集 {1,2}
a ^ b # 对称差 {1,2,4,5}
# 判断关系
{1,2} <= {1,2,3} # 子集 True
{1,2,3}.issuperset({1,2}) # 超集 True-- 2025 年 9 月 23 日止 --
切片 slice
- 切片
slice是按“起始:结束:步长”的规则从序列里取出一段子序列的语法和机制 seq[start:stop:step]等价于seq[slice(start, stop, step)]- 适用于
list/tuple/str/bytes/bytearray等序列类型 - 任一位置可省略
- 负索引从尾部计:
-1是最后一个 - 切片不会抛 IndexError:超出范围会自动截断
# 切片对象
sl = slice(1, 5, 2)
[10,11,12,13,14,15][sl] # [11, 13]
seq[start : stop : step]
# start 起始下标(含)
# stop 结束下标(不含)
# step 步长,默认 1,可为负
s = "abcdefg"
s[1:4] # 'bcd'
s[:3] # 'abc'
s[4:] # 'efg'
s[::2] # 'aceg'
s[-4:-1] # 'def'
s[::-1] # 'gfedcba' 反转
[1,2,3][0:10] # [1,2,3]
# 赋值/删除切片(仅 list 等可变序列)
a = [0,1,2,3,4,5]
a[2:5] = [20, 30] # → [0,1,20,30,5] # 替换并缩短
a[2:2] = [7,8] # → [0,1,7,8,20,30,5] # 在索引 2 处插入
a[::2] = [9,9,9,9] # 步长切片赋值,右侧长度必须匹配元素个数
del a[1:4] # 删除片段
# 使用 sorted
# 创建一个学生成绩列表
scores = [85, 92, 78, 90, 88, 95, 82, 87, 91, 89]
# 获取前5名学生的成绩
# 使用sorted函数对scores列表进行排序,并使用reverse=True参数进行降序排序
# 然后使用切片[:5]获取前5名学生的成绩
top_five = sorted(scores, reverse=True)[:5]
print("前5名成绩:", top_five) # 输出: [95, 92, 91, 90, 89]
# 获取后3名学生的成绩
# 使用sorted函数对scores列表进行排序,并使用reverse=False参数进行升序排序
# 然后使用切片[:3]获取后3名学生的成绩
bottom_three = sorted(scores)[:3]
print("后3名成绩:", bottom_three) # 输出: [78, 82, 85]迭代 iteration
- 可迭代对象(iterable):能被
for ... in遍历的东西,比如list/tuple/str/dict/set/range、生成器等。判定标准:对象实现了__iter__(),或是序列实现了__len__和__getitem__(从 0 起)。 - 迭代器(iterator):有状态、一次性产出下一个元素的对象。判定标准:实现
__iter__()(返回自身)和__next__();耗尽时__next__抛StopIteration。
# for x in obj 的幕后流程:
it = iter(obj) # 调 __iter__ 得到迭代器
while True:
try:
x = next(it) # 调 __next__
except StopIteration:
break
# 使用 x
# 常用写法
for x in [1,2,3]: ...
for ch in "abc": ...
for k, v in {"a":1, "b":2}.items(): ...
for i in range(5): ...
# 带索引
for i, x in enumerate(["a","b","c"], start=1):
...
# 并行迭代
for a, b in zip([1,2,3], [10,20,30]):
...
# 推导式(语法糖,返回容器或集合)
squares = [x*x for x in range(10)] # 列表推导
evens = {x for x in range(10) if x%2==0} # 集合推导
mapping = {x: x*x for x in range(5)} # 字典推导
# 生成器函数:用 yield 按需产出元素;天然是迭代器。
def countdown(n):
while n > 0:
yield n # 产出 n,并暂停在这里
n -= 1 # 下次继续从这里往后跑
g = countdown(3)
next(g) # 3
next(g) # 2
next(g) # 1
next(g) # StopIteration 异常(迭代结束)
# 通常用 for 最方便:
for x in countdown(3): # 3, 2, 1
print(x)
# 列表推导(立即生成列表,占用对应内存)
lst = [x*x for x in range(10)] # [0, 1, 4, ..., 81]
# 生成器表达式(惰性,不占大内存)
gen = (x*x for x in range(10))
print(next(gen)) # 0
print(next(gen)) # 1
print(list(gen)) # [4, 9, 16, 25, 36, 49, 64, 81] # 把剩下的取完
# 生成器表达式是迭代器,只能遍历一次
# 遍历完后,再次遍历会抛出 StopIteration 异常
print(list(gen)) # [] 已经耗尽
iterable_iter = iter([1,2,3]) # 从可迭代得到迭代器
next(iterable_iter) # -> 1
# itertools 小而美(懒序列工具箱)
from itertools import islice, count, chain
# .count(start=0, step=1) 生成一个“无限等差序列”
# .islice 两种调用形式
# .islice(iterable, stop)
# .islice(iterable, start, stop[, step])
# 对任意可迭代对象做“切片”,返回惰性子序列(像 `seq[start:stop:step]`,但不要求是序列)
print(list(islice(count(10, 2), 3))) # [10, 12, 14] 无限序列切片
# .chain(*iterables) 把多个可迭代对象首尾相接,像把它们“串起来”
# 不会复制数据,逐个迭代。
# 比 `sum(lists, [])` 拼接列表高效很多(后者有 O(n²) 拷贝风险)
list(chain([1,2], (3,4), {5,6})) # [1, 2, 3, 4, 5, 6]
list(chain([1,2], [3,4])) # [1,2,3,4]列表生成式
用一行表达式构造列表的语法糖,等价于“循环 + 条件 + append”
[ 表达式 for 变量 in 可迭代对象 if 条件 ]
# 等价于
out = []
for 变量 in 可迭代对象:
if 条件:
out.append(表达式)
# 平方表
squares = [x*x for x in range(6)] # [0,1,4,9,16,25]
# 过滤:只要偶数的平方
even_sq = [x*x for x in range(10) if x % 2 == 0] # [0,4,16,36,64]
# 条件表达式(内联三元运算)
labels = ["odd" if x % 2 else "even" for x in range(5)]
# 等价循环:if…else 放在表达式位置,不是过滤
# 笛卡尔积(所有配对)
pairs = [(i, j) for i in range(3) for j in range(2)]
# → [(0,0),(0,1),(1,0),(1,1),(2,0),(2,1)] # 左到右依次展开
# 扁平化二维列表
matrix = [[1,2,3],[4,5,6]]
flat = [x for row in matrix for x in row] # [1,2,3,4,5,6]
data = ["a","b","c"]
with_idx = [(i, x) for i, x in enumerate(data, start=1)] # [(1,'a'),...]
zipped = [a+b for a, b in zip("ABC", "xyz")] # ['Ax','By','Cz']
# 集合推导:自动去重
s = {x % 3 for x in range(10)} # {0,1,2}
# 字典推导:键值对
d = {x: x*x for x in range(5)} # {0:0, 1:1, ...}
# 清洗数据:去空白并过滤空串
clean = [s.strip() for s in lines if s.strip()]
# 展开并过滤
words = [w.lower() for line in lines for w in line.split() if w]
# 仅保留字母数字
import re
norm = [re.sub(r"\W+", "", s) for s in strings]
# 海象运算符 := 表达式里复用中间结果
# n 只算一次,既做过滤又收集
sizes = [n for s in files if (n := s.stat().st_size) > 0]正则表达式
一门描述文本模式的小语言,用来查找、提取、替换字符串中符合某种规则的片段。比如:匹配邮箱、手机号、日期、URL 等。
表达式符号
\d数字[0-9]\w单词字符[A-Za-z0-9_]\s空白(空格/制表/换行)\D \W \S大写为取反\t匹配一个 tab.:匹配任意单个字符,除了换行符(\n)*:匹配前面的内容出现0次或多次+:匹配前面的内容出现1次或多次?:匹配前面的内容出现0次或1次{n}:匹配前面的内容出现n次{n,m}:匹配前面的内容出现n到m次*?+???{m,n}?加?惰性(非贪婪)尽量少匹配[]:匹配括号内的任意一个字符[abc]:a 或 b 或 c[^abc]:非 a/b/c^:匹配字符串的开头$:匹配字符串的结尾|:表示“或”,比如A|B可以匹配A或B\b单词边界,\B非单词边界(左/右一侧是\w,另一侧是\W)\A字符串开头,\Z字符串末尾(不受多行影响)( … )捕获分组;\1、\2回溯引用(?: … )非捕获分组(只分组不记号)(?P<name> … )命名分组;(?P=name)引用
字面量与转义
- 直接写字符就是匹配它自己:
cat匹配 “cat” - 特殊字符需要转义:
\.匹配字面点,\(\)\+等等
断言
先行/后行(不消耗字符,只检查“前后邻居”)
(?=…)正向先行:后面必须是 …(?!…)负向先行:后面不能是 …(?<=…)正向后行:前面必须是 …(?<!…)负向后行:前面不能是 …
常用 flags(模式修饰符)
re.I大小写不敏感re.M多行:^/$作用于每行re.S(DOTALL)让.匹配换行re.X(VERBOSE)允许在正则里加空白和注释,便于书写
import re
# 1) 查找
text = "2023-08-20 is a date, and 2024-01-01 is also a date."
m = re.search(r"\d{4}-\d{2}-\d{2}", text) # 找第一个匹配
if m:
m.group(0) # 整个匹配
m.start(), m.end()
# 2) 全部匹配
all_dates = re.findall(r"\d{4}-\d{2}-\d{2}", text)
# 3) 迭代匹配(更省内存 & 有位置信息)
for m in re.finditer(r"\b\w+\b", text):
print(m.group(), m.span())
# 4) 替换
re.sub(r"\s+", " ", text) # 多空白折叠为单空格
s = "123-456-7890"
re.sub(r"(\d{3})-(\d{4})", r"\1 \2", s) # 用分组反向引用
# 5) 分割
re.split(r"[,\s]+", "a, b c") # -> ['a','b','c']
# 6) 预编译(频繁使用时更快)
pat = re.compile(r"\b([A-Za-z]+)=(\d+)\b")
pat.search(text)
print(re.findall(r"[^abc]+", "abz1cxy")) # ['z1', 'xy']
s = "scatter catalog cat"
print(re.findall(r"\Bcat\B", s)) # 左右都在“单词内部”
s = "10kg 12g 8kg"
re.findall(r"\d+(?=kg)", s) # ['10', '8']
# 解释:匹配的结果是数字本身;先行断言只检查“后面是不是 kg”。
s = "abc abc1 ab12 xyz"
re.findall(r"\b[a-zA-Z]+\b(?!\d)", s) # ['abc', 'xyz']
# 解释:\b[a-zA-Z]+\b 是独立的字母词;(?!\d) 要求其后面不是数字。
s = "pay $12 and $3.5, not 7 or $x"
re.findall(r"(?<=\$)\d+(?:\.\d+)?", s) # ['12', '3.5']
# 解释:只把数字取出来;(?<=\$) 确保数字前面是美元符号。
s = "visit example.com, mail a@foo.example.com"
re.findall(r"(?<!@)\bexample\.com\b", s) # ['example.com']
# 解释:如果前面是 @(出现在邮箱里),就被排除。-- 2025 年 9 月 24 日止 --
配套代码:vsme/learn-python