Python语法
Python 用缩进代替花括号、一切皆对象,这两条规则决定了它的语法风格和绝大多数行为。缩进不仅是排版约定,更是语法的一部分——错误缩进直接抛 IndentationError。动态类型让代码简洁,但变量绑定的真实规则(对象引用 + 作用域查找)是初学者最容易踩坑的地方。
数据类型
Python 数据类型按"是否可变"分为两大阵营,这是理解一切 Python 行为的钥匙:
| 类型 | 可变性 | 说明 |
|---|---|---|
int / float / bool | 不可变 | 数字;bool 是 int 的子类 |
str | 不可变 | Unicode 字符串,切片、拼接产生新对象 |
tuple | 不可变 | 定长序列,可哈希(可作 dict 键) |
frozenset | 不可变 | 不可变集合 |
list | 可变 | 动态数组,尾部操作 O(1) |
dict | 可变 | 哈希表,O(1) 查找 |
set | 可变 | 哈希集合,去重、成员判断 |
可变与不可变的区别在"原地修改是否会改变对象身份":list.append() 原地改,所有引用都看到变化;str 的任何修改都生成新对象。这个区别直接决定函数传参时的表现。
a = [1, 2]
b = a # b 与 a 指向同一列表
b.append(3) # a 也变成 [1, 2, 3]
s = "ab"
t = s.upper() # t 是新字符串,s 不变变量与作用域
Python 变量是"名字绑定到对象",不是"盒子装值"。赋值 x = 1 是把名字 x 绑定到整数对象 1,重新赋值只是换绑到新对象。
作用域查找遵循 LEGB 规则:Local(局部)→ Enclosing(外层函数)→ Global(模块级)→ Built-in(内置)。
count = 0 # Global
def outer():
count = 1 # Enclosing
def inner():
count = 2 # Local
return count
return inner()赋值即声明
在函数内对变量赋值,Python 默认把它当成局部变量。想改全局变量必须用 global,改外层函数变量用 nonlocal——否则会抛 UnboundLocalError(看起来是"用了未定义变量")。
count = 0
def wrong():
print(count) # ❌ UnboundLocalError:count 在函数内被赋值,被当作局部
count = 1
def right():
global count
count = 1 # ✅ 修改模块级变量控制流
if / for / while 语法与 C 系语言接近,差异在两个地方:
- 条件不需要括号,块用冒号 + 缩进
for遍历的是可迭代对象(list、dict、range、生成器),不是下标
# 遍历字典:默认遍历键
d = {"a": 1, "b": 2}
for k in d: # k = "a", "b"
print(k, d[k])
for k, v in d.items(): # 同时拿键值
print(k, v)
# range 生成整数序列
for i in range(3): # 0, 1, 2
print(i)Python 3.10+ 引入 match 语句,比 if-elif 更适合结构化匹配:
def describe(obj):
match obj:
case 0:
return "零"
case [x, y]: # 序列模式
return f"两点: {x}, {y}"
case {"name": n}: # 字典模式
return f"名字: {n}"
case _: # 兜底
return "其他"函数与参数传递
Python 函数传参传递的是"对象引用"——形参和实参指向同一对象,但重新绑定形参不影响实参。这既不是 C 的值传递,也不是 C++ 的引用传递,而是"传对象引用":
def f(lst, n):
lst.append(4) # 修改对象本身 → 外部可见
n = 99 # 重新绑定形参 → 外部 n 不变
lst = [100] # 重新绑定形参 → 外部 lst 不变
arr = [1, 2, 3]
num = 5
f(arr, num)
# arr = [1, 2, 3, 4],num = 5默认参数陷阱
默认参数只在定义时求值一次。可变默认值会被所有调用共享:
def add_item(item, bag=[]): # ❌ bag 是同一个列表
bag.append(item)
return bag
add_item("a") # ['a']
add_item("b") # ['a', 'b'] ← 上一次的结果还在正确写法用 None 占位,函数体内创建:
def add_item(item, bag=None):
if bag is None:
bag = []
bag.append(item)
return bag常用内置函数
| 函数 | 作用 | 示例 |
|---|---|---|
len() | 长度 | len("abc") → 3 |
range() | 整数序列 | list(range(3)) → [0,1,2] |
enumerate() | 带索引遍历 | list(enumerate("ab")) → [(0,'a'),(1,'b')] |
zip() | 并行打包 | list(zip([1,2],['a','b'])) → [(1,'a'),(2,'b')] |
sorted() | 排序(返回新列表) | sorted([3,1,2]) → [1,2,3] |
isinstance() | 类型检查 | isinstance(1, int) → True |
map / filter / reduce 与推导式的关系见 Python函数式编程;async/await 与 GIL 见 Python异步编程;面向对象特性见 Python 主文档。
文件操作
文件读写用内置 open(),标准姿势是 with 语句自动关闭(异常时也保证关闭,等价 try/finally):
# 写文件(覆盖)
with open("out.txt", "w", encoding="utf-8") as f:
f.write("第一行\n")
# 读文件(逐行,大文件内存友好)
with open("out.txt", "r", encoding="utf-8") as f:
for line in f:
print(line.strip())
# 追加 / 二进制 / 同时读写
with open("log.txt", "a") as f: # a=追加
f.write("更多内容\n")
with open("img.png", "rb") as f: # b=二进制
data = f.read()| 模式 | 含义 | 文件不存在时 |
|---|---|---|
r | 只读(默认) | 报错 |
w | 写(清空) | 创建 |
a | 追加 | 创建 |
r+ | 读写 | 报错 |
rb / wb | 二进制读写 | 同 r/w |
os 与 pathlib
跨平台路径与目录操作用 os.path 或更现代的 pathlib.Path:
import os
from pathlib import Path
# os 方式
os.path.join("dir", "a.txt") # 平台正确拼接
os.path.exists("a.txt")
os.makedirs("dir", exist_ok=True) # 建目录(已存在不报错)
os.listdir(".") # 列出目录
# pathlib 方式(推荐,更直观)
p = Path("dir") / "a.txt" # / 拼接路径
p.exists(); p.is_file(); p.name; p.suffix # 存在/文件/文件名/扩展名
p.read_text(); p.write_text("hi") # 一行读写
p.parent.mkdir(parents=True, exist_ok=True) # 建父目录用 pathlib 代替字符串拼接
Path 用 / 运算符拼路径、天然跨平台(Windows 自动用 \),避免 os.path.join 的字符串胶水。Python 3.4+ 标准库,现代代码首选。
迭代器协议
迭代器协议 = __iter__() 返回迭代器 + 迭代器的 __next__() 产出下一个值;for x in obj 内部就是循环调用 next() 直到 StopIteration:
# for 循环的底层等价
it = iter([1, 2, 3]) # iter() 调 __iter__
while True:
try:
x = next(it) # next() 调 __next__
except StopIteration:
break
print(x)
# 自定义可迭代对象
class CountDown:
def __init__(self, n): self.n = n
def __iter__(self): return self # 返回迭代器(自身)
def __next__(self):
if self.n <= 0: raise StopIteration # 结束信号
self.n -= 1
return self.n + 1
for x in CountDown(3): # 3 2 1
print(x)生成器就是迭代器
yield 生成器自动实现 __iter__/__next__,是手写迭代器协议的捷径(见 Python函数式编程 的生成器章节);iter()/next() 内建函数适用于任何可迭代对象,enumerate/zip 等返回的也是迭代器。