第2章 基础语法
学习目标
完成本章学习后,读者将能够:
- 掌握Python注释的编写规范与文档字符串(Docstring)标准
- 理解Python变量模型的本质——引用语义与对象模型
- 熟练运用f-string等格式化方法进行专业级输出
- 理解Python缩进机制的设计原理与工程意义
- 遵循PEP 8规范编写符合行业标准的代码
2.1 注释与文档
2.1.1 单行注释
Python使用#标记单行注释,解释器会忽略从#到行末的所有内容:
# 计算圆的面积
radius = 5
area = 3.14159 * radius ** 2 # 面积公式:S = πr²2.1.2 多行注释与文档字符串
Python没有真正的多行注释语法。三引号字符串("""或''')在模块/类/函数级别会成为文档字符串(Docstring),而非注释:
"""
模块级文档字符串
描述整个模块的功能、作者、版本等信息。
可通过 __doc__ 属性或 help() 函数访问。
"""
def calculate_bmi(weight: float, height: float) -> float:
"""计算身体质量指数(BMI)
使用国际标准公式:BMI = 体重(kg) / 身高(m)²
Args:
weight: 体重,单位千克(kg)
height: 身高,单位米(m)
Returns:
BMI值,保留一位小数
Raises:
ValueError: 当身高或体重为非正数时
Examples:
>>> calculate_bmi(70, 1.75)
22.9
"""
if weight <= 0 or height <= 0:
raise ValueError("体重和身高必须为正数")
return round(weight / height ** 2, 1)学术注记:Python文档字符串遵循PEP 257规范。主流格式包括Google风格、NumPy风格和Sphinx/reST风格。上述示例采用Google风格,因其可读性最佳,且可被Sphinx自动解析生成API文档。
2.1.3 注释最佳实践
# 好的注释:解释"为什么"(Why),而非"是什么"(What)
# 使用二分查找替代线性搜索,将时间复杂度从O(n)降至O(log n)
def binary_search(arr: list, target: int) -> int:
pass
# 不好的注释:重复代码内容
x = 10 # 设置x等于10
# 好的注释:解释不明显的业务逻辑
# 边界条件:空列表或单元素列表天然有序,直接返回
if len(arr) <= 1:
return arr
# 特殊标记注释(IDE和工具可识别)
# TODO: 添加并发安全机制
# FIXME: 当输入为空列表时返回值不正确
# NOTE: 此函数会修改传入列表的原地顺序
# HACK: 临时绕过第三方库的编码问题,待升级后移除
# XXX: 此处逻辑复杂,需要仔细审查2.2 变量与对象模型
2.2.1 Python的对象模型
理解Python变量的关键在于:Python中变量是对象的引用(标签),而非存储值的容器。
C语言模型: Python模型:
┌──────┐ name ──┐
│ name │──→ 42 age ──┤
└──────┘ │
┌─────┐ ┌──────┴──────┐
│ age │──→ 25 │ int(42) │
└─────┘ │ id: 1407... │
│ value: 42 │
│ type: int │
└─────────────┘
┌─────────────┐
│ int(25) │
│ id: 1407... │
│ value: 25 │
│ type: int │
└─────────────┘x = 42
print(id(x)) # 对象的内存地址(标识)
print(type(x)) # 对象的类型
print(x) # 对象的值
a = 42
b = 42
print(a is b) # True - 小整数缓存(-5到256)
a = 257
b = 257
print(a is b) # 可能False - 超出缓存范围
print(a == b) # True - 值相等学术注记:CPython对小整数(-5到256)和短字符串进行**驻留(Interning)**优化,相同值的对象共享同一内存地址。这是解释器实现细节,不应在业务逻辑中依赖
is进行值比较。
2.2.2 可变与不可变对象
这是Python对象模型中最重要的区分:
| 类型 | 可变性 | 示例 | 赋值行为 |
|---|---|---|---|
| int, float, bool | 不可变 | x = 1 | 修改时创建新对象 |
| str | 不可变 | s = "hello" | 修改时创建新对象 |
| tuple | 不可变 | t = (1, 2) | 内容不可修改 |
| list | 可变 | l = [1, 2] | 原地修改 |
| dict | 可变 | d = {"a": 1} | 原地修改 |
| set | 可变 | s = {1, 2} | 原地修改 |
# 不可变对象:修改创建新对象
x = 42
print(id(x)) # 例如 1407357984
x = x + 1
print(id(x)) # 不同!新对象
# 可变对象:原地修改
my_list = [1, 2, 3]
print(id(my_list)) # 例如 2305843014
my_list.append(4)
print(id(my_list)) # 相同!原地修改
# 引用语义导致的陷阱
a = [1, 2, 3]
b = a # b和a指向同一个列表对象
b.append(4)
print(a) # [1, 2, 3, 4] - a也被修改了!
# 正确的复制方式
c = a.copy() # 浅拷贝
c = a[:] # 浅拷贝(切片语法)
import copy
d = copy.deepcopy(a) # 深拷贝2.2.3 变量命名规则
语法规则(必须遵守):
- 只能包含字母、数字、下划线
- 不能以数字开头
- 不能使用Python关键字
- 区分大小写
# 合法命名
name = "Alice"
user_name = "Bob"
_user = "David"
user2 = "Eve"
π = 3.14159 # Unicode标识符(不推荐)
# 非法命名
2user = "Alice" # 不能以数字开头
user-name = "Bob" # 不能包含连字符
class = "Math" # 不能使用关键字PEP 8命名约定:
# 变量和函数:snake_case
user_name = "Alice"
def calculate_total_price():
pass
# 常量:UPPER_SNAKE_CASE
MAX_CONNECTIONS = 100
DEFAULT_TIMEOUT = 30
# 类名:PascalCase
class UserProfile:
pass
# 私有属性:单下划线前缀(约定)
class MyClass:
_internal_state = None # 提示:内部使用,但不强制
# 名称修饰:双下划线前缀
class MyClass:
__private = 42 # 实际存储为 _MyClass__private
# 魔术方法:双下划线包围
class MyClass:
def __init__(self):
pass
def __repr__(self):
pass2.2.4 赋值语法
# 基本赋值
x = 10
# 多重赋值
x, y, z = 1, 2, 3
# 链式赋值
x = y = z = 0
# 交换变量(Pythonic方式)
x, y = 10, 20
x, y = y, x
# 解包赋值
numbers = [1, 2, 3]
a, b, c = numbers
# 扩展解包(Python 3.0+)
first, *rest = [1, 2, 3, 4, 5]
print(first, rest) # 1 [2, 3, 4, 5]
*head, last = [1, 2, 3, 4, 5]
print(head, last) # [1, 2, 3, 4] 5
first, *middle, last = [1, 2, 3, 4, 5]
print(first, middle, last) # 1 [2, 3, 4] 5
# 海象运算符(Python 3.8+,赋值表达式)
if (n := len(data)) > 10:
print(f"数据过长:{n}条记录")
# 等价于
n = len(data)
if n > 10:
print(f"数据过长:{n}条记录")2.2.5 变量删除
x = 10
del x
data = {"a": 1, "b": 2, "c": 3}
del data["b"]
print(data) # {'a': 1, 'c': 3}2.2.6 Python内存管理机制
理解Python的内存管理对于编写高效代码至关重要:
引用计数(Reference Counting)
Python主要使用引用计数来管理内存,每个对象维护一个引用计数器:
import sys
a = [1, 2, 3]
print(sys.getrefcount(a) - 1) # 1 (减去getrefcount自身的临时引用)
b = a
print(sys.getrefcount(a) - 1) # 2
c = a
print(sys.getrefcount(a) - 1) # 3
del b
print(sys.getrefcount(a) - 1) # 2
import gc
gc.collect()垃圾回收(Garbage Collection)
引用计数无法处理循环引用,Python使用分代垃圾回收器处理这类情况:
import gc
gc.disable()
class Node:
def __init__(self):
self.ref = None
a = Node()
b = Node()
a.ref = b
b.ref = a
del a
del b
gc.enable()
collected = gc.collect()
print(f"回收了 {collected} 个对象")内存池机制
CPython使用内存池(PyMalloc)优化小对象的分配:
import sys
sizes = [sys.getsizeof(i) for i in range(100)]
print(f"整数对象大小: {sizes[0]} 字节")
print(f"列表对象大小: {sys.getsizeof([])} 字节")
print(f"字典对象大小: {sys.getsizeof({})} 字节")学术注记:Python 3.12引入了PEP 684——每子解释器GIL,允许每个子解释器拥有独立的GIL。Python 3.13的自由线程模式(PEP 703)则完全移除了GIL,这对内存管理策略产生了深远影响。
2.2.7 对象内省(Introspection)
Python提供了丰富的内省能力,这是动态语言的核心特性之一:
class Person:
species = "Homo sapiens"
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def greet(self) -> str:
return f"Hello, I'm {self.name}"
p = Person("Alice", 30)
print(type(p)) # <class '__main__.Person'>
print(p.__class__) # <class '__main__.Person'>
print(p.__dict__) # {'name': 'Alice', 'age': 30}
print(p.__class__.__bases__) # (<class 'object'>,)
print(hasattr(p, 'name')) # True
print(hasattr(p, 'gender')) # False
print(getattr(p, 'name')) # Alice
print(getattr(p, 'gender', 'N/A')) # N/A (默认值)
setattr(p, 'gender', 'Female')
print(p.gender) # Female
delattr(p, 'gender')
print(hasattr(p, 'gender')) # False
print(dir(p))使用inspect模块进行深度内省:
import inspect
print(inspect.getmembers(p))
print(inspect.getsource(Person.greet))
print(inspect.signature(Person.__init__))
print(inspect.getmro(Person))2.2.8 类型注解与静态类型检查
Python 3.5+引入了类型注解(Type Hints),支持静态类型检查:
from typing import Optional, Union, List, Dict, Callable, TypeVar, Generic
T = TypeVar('T')
def process_data(
items: List[T],
key: Optional[str] = None,
transform: Optional[Callable[[T], T]] = None,
) -> Dict[str, List[T]]:
"""处理数据列表
Args:
items: 输入数据列表
key: 可选的分组键
transform: 可选的转换函数
Returns:
分组后的字典
"""
result: Dict[str, List[T]] = {}
if transform:
items = [transform(item) for item in items]
result[key or "default"] = items
return result
class Container(Generic[T]):
def __init__(self, value: T):
self.value = value
def get(self) -> T:
return self.value
container: Container[int] = Container(42)
def parse_value(s: str) -> Union[int, float, str]:
try:
return int(s)
except ValueError:
try:
return float(s)
except ValueError:
return s
result: Union[int, float, str] = parse_value("42")类型检查工具:
pip install mypy
mypy your_script.pyfrom typing import TypedDict, Literal, Final, Protocol
class PersonDict(TypedDict):
name: str
age: int
gender: Literal['male', 'female', 'other']
MAX_SIZE: Final[int] = 100
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle:
def draw(self) -> None:
print("Drawing circle")
def render(shape: Drawable) -> None:
shape.draw()工程实践:类型注解不改变Python的运行时行为,但能显著提升代码可维护性和IDE支持。推荐在所有公共API中使用类型注解,并配置mypy进行静态检查。
2.3 输入与输出
2.3.1 print函数详解
# 基本输出
print("Hello, World!")
# 多参数输出(默认空格分隔)
print("Hello", "World", "Python") # Hello World Python
# 自定义分隔符
print("2024", "01", "15", sep="/") # 2024/01/15
print("A", "B", "C", sep="-") # A-B-C
# 自定义结束符
print("Loading", end="")
for i in range(3):
print(".", end="", flush=True)
print(" Done!")
# 进度条效果
import time
for i in range(101):
print(f"\r进度: {i}%", end="", flush=True)
time.sleep(0.02)
print()
# 输出到标准错误流
import sys
print("错误信息", file=sys.stderr)2.3.2 字符串格式化
f-string(Python 3.6+,推荐方案)
f-string是Python最现代、最高效的字符串格式化方式:
name = "Alice"
age = 25
# 基本用法
print(f"姓名:{name},年龄:{age}")
# 表达式求值
print(f"2的10次方:{2 ** 10}")
print(f"姓名大写:{name.upper()}")
# 浮点数格式化
pi = 3.14159265
print(f"π ≈ {pi:.2f}") # π ≈ 3.14
print(f"π ≈ {pi:.6f}") # π ≈ 3.141593
# 整数格式化
num = 42
print(f"二进制:{num:b}") # 二进制:101010
print(f"八进制:{num:o}") # 八进制:52
print(f"十六进制:{num:x}") # 十六进制:2a
print(f"十六进制:{num:X}") # 十六进制:2A
# 对齐与填充
name = "Alice"
print(f"|{name:>10}|") # 右对齐:| Alice|
print(f"|{name:<10}|") # 左对齐:|Alice |
print(f"|{name:^10}|") # 居中: | Alice |
print(f"|{name:*^10}|") # 居中填充:|**Alice***|
# 千分位分隔
value = 1234567.89
print(f"金额:{value:,.2f}") # 金额:1,234,567.89
# 科学计数法
print(f"科学计数:{value:e}") # 科学计数:1.234568e+06
# 百分比
ratio = 0.856
print(f"完成率:{ratio:.1%}") # 完成率:85.6%
# 日期格式化
from datetime import datetime
now = datetime.now()
print(f"当前时间:{now:%Y-%m-%d %H:%M:%S}")
# 嵌套格式化(Python 3.12+)
width = 10
precision = 2
print(f"{pi:{width}.{precision}f}") # 3.14
# 调试输出(Python 3.8+)
x = 42
print(f"{x = }") # x = 42
print(f"{x = :08b}") # x = 00101010format方法
print("姓名:{},年龄:{}".format(name, age))
print("姓名:{0},年龄:{1},重复:{0}".format(name, age))
print("姓名:{name},年龄:{age}".format(name="Alice", age=25))
data = {"name": "Alice", "age": 25}
print("姓名:{name},年龄:{age}".format(**data))%格式化(旧式,仅作了解)
print("姓名:%s,年龄:%d" % ("Alice", 25))
print("π ≈ %.2f" % 3.14159)工程实践:新项目统一使用f-string。format方法仅在需要动态模板时使用。%格式化已不推荐。
2.3.3 input函数
# 基本输入
name = input("请输入你的名字:")
# 类型转换
age = int(input("请输入你的年龄:"))
height = float(input("请输入你的身高(米):"))
# 安全输入模式
def safe_int_input(prompt: str, min_val: int = 0, max_val: int = 150) -> int:
"""安全获取整数输入"""
while True:
try:
value = int(input(prompt))
if min_val <= value <= max_val:
return value
print(f"请输入{min_val}到{max_val}之间的整数")
except ValueError:
print("请输入有效的整数")
age = safe_int_input("请输入你的年龄:", 0, 150)
# 密码输入(不回显)
import getpass
password = getpass.getpass("请输入密码:")2.4 缩进与代码块
2.4.1 缩进机制
Python使用缩进(Indentation)而非花括号来表示代码块的层次关系,这是Python最具争议也最具特色的设计决策:
if True:
print("缩进4个空格") # 属于if代码块
if True:
print("缩进8个空格") # 属于嵌套if代码块
print("回到顶层") # 不属于任何代码块设计哲学:Guido van Rossum选择缩进语法的原因是——代码被阅读的次数远多于编写的次数,强制缩进消除了代码格式不一致的问题,使Python代码天然具有良好的可读性。这一设计在大型项目中显著降低了代码审查的认知负担。
2.4.2 缩进规则
# 规则1:统一使用4个空格(PEP 8)
if True:
print("4个空格")
# 规则2:同一代码块缩进必须一致
if True:
print("第1行")
print("第2行") # 正确:与上一行缩进一致
# 规则3:续行使用额外缩进
total = (first_variable
+ second_variable
+ third_variable)
# 规则4:悬挂缩进
def long_function_name(
var_one, var_two,
var_three, var_four):
print(var_one)2.4.3 常见缩进错误
# 错误1:缩进不一致 → IndentationError
if True:
print("4个空格")
print("6个空格") # IndentationError
# 错误2:缺少缩进 → IndentationError
if True:
print("没有缩进") # IndentationError
# 错误3:混用Tab和空格 → TabError
if True:
print("空格")
print("Tab") # TabError
# 错误4:不必要的缩进
print("顶层代码")
print("多余缩进") # IndentationError工程实践:在编辑器中配置"将Tab转换为空格",杜绝Tab和空格混用问题。VS Code默认已启用此设置。
2.5 运算符
2.5.1 算术运算符
print(10 + 3) # 13 加法
print(10 - 3) # 7 减法
print(10 * 3) # 30 乘法
print(10 / 3) # 3.3333... 除法(返回float)
print(10 // 3) # 3 整除(向下取整)
print(10 % 3) # 1 取模(余数)
print(10 ** 3) # 1000 幂运算
# 注意整除的负数行为
print(-7 // 2) # -4 向负无穷方向取整
print(7 // -2) # -4
# divmod同时获取商和余数
quotient, remainder = divmod(10, 3)
print(quotient, remainder) # 3 12.5.2 比较运算符
print(10 == 10) # True 等于
print(10 != 5) # True 不等于
print(10 > 5) # True 大于
print(10 < 5) # False 小于
print(10 >= 10) # True 大于等于
print(10 <= 5) # False 小于等于
# Python支持链式比较
x = 5
print(1 < x < 10) # True,等价于 1 < x and x < 10
print(1 < x > 3) # True,等价于 1 < x and x > 3
# is vs ==
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True - 值相等
print(a is b) # False - 不是同一对象
c = a
print(a is c) # True - 同一对象2.5.3 逻辑运算符
print(True and False) # False
print(True or False) # True
print(not True) # False
# 短路求值
x = 0
if x != 0 and 10 / x > 1: # 不会执行除法
pass
# 返回实际值(非布尔值)
print(1 and 2) # 2 - and返回最后一个为真的值
print(0 and 2) # 0 - and返回第一个为假的值
print(1 or 2) # 1 - or返回第一个为真的值
print(0 or 2) # 2 - or返回最后一个为假的值
print(0 or "" or None) # None
# 实用模式
name = input("姓名:") or "匿名用户"2.5.4 位运算符
print(0b1010 & 0b1100) # 0b1000 按位与
print(0b1010 | 0b1100) # 0b1110 按位或
print(0b1010 ^ 0b1100) # 0b0110 按位异或
print(~0b1010) # -11 按位取反
print(0b1010 << 2) # 0b101000 左移
print(0b1010 >> 2) # 0b10 右移
# 实用:权限标志
READ = 0b0001
WRITE = 0b0010
EXECUTE = 0b0100
permission = READ | WRITE
print(bool(permission & READ)) # True - 有读权限
print(bool(permission & EXECUTE)) # False - 无执行权限2.5.5 运算符优先级
从高到低:
| 优先级 | 运算符 | 说明 |
|---|---|---|
| 1 | ** | 幂运算 |
| 2 | +x, -x, ~x | 一元运算符 |
| 3 | *, /, //, % | 乘除 |
| 4 | +, - | 加减 |
| 5 | <<, >> | 位移 |
| 6 | & | 按位与 |
| 7 | ^ | 按位异或 |
| 8 | | | 按位或 |
| 9 | ==, !=, <, >, <=, >=, is, in | 比较 |
| 10 | not | 逻辑非 |
| 11 | and | 逻辑与 |
| 12 | or | 逻辑或 |
| 13 | if-else | 条件表达式 |
工程实践:不要依赖运算符优先级,复杂表达式使用括号明确意图。
2 + 3 * 4应写为2 + (3 * 4)。
2.5.6 成员运算符与身份运算符
fruits = ["apple", "banana", "cherry"]
print("apple" in fruits) # True
print("orange" not in fruits) # True
text = "Hello, Python"
print("Python" in text) # True
print("python" in text) # False (区分大小写)
scores = {"Alice": 95, "Bob": 87}
print("Alice" in scores) # True (检查键)
print(95 in scores) # False (不检查值)
a = 256
b = 256
print(a is b) # True (小整数缓存)
a = 257
b = 257
print(a is b) # False (超出缓存范围)
print(a == b) # True (值相等)
x = None
print(x is None) # True (推荐用is检查None)
print(x == None) # True (不推荐)最佳实践:
is用于身份检查(是否同一对象),==用于值比较。检查None时应使用x is None而非x == None。
2.5.7 运算符重载
Python允许通过魔术方法重载运算符,实现自定义类型的行为:
import math
class Vector2D:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
def __repr__(self) -> str:
return f"Vector2D({self.x}, {self.y})"
def __add__(self, other: "Vector2D") -> "Vector2D":
return Vector2D(self.x + other.x, self.y + other.y)
def __sub__(self, other: "Vector2D") -> "Vector2D":
return Vector2D(self.x - other.x, self.y - other.y)
def __mul__(self, scalar: float) -> "Vector2D":
return Vector2D(self.x * scalar, self.y * scalar)
def __rmul__(self, scalar: float) -> "Vector2D":
return self.__mul__(scalar)
def __eq__(self, other: object) -> bool:
if not isinstance(other, Vector2D):
return NotImplemented
return self.x == other.x and self.y == other.y
def __abs__(self) -> float:
return math.sqrt(self.x ** 2 + self.y ** 2)
def __bool__(self) -> bool:
return bool(self.x or self.y)
v1 = Vector2D(3, 4)
v2 = Vector2D(1, 2)
print(v1 + v2) # Vector2D(4, 6)
print(v1 - v2) # Vector2D(2, 2)
print(v1 * 2) # Vector2D(6, 8)
print(2 * v1) # Vector2D(6, 8)
print(abs(v1)) # 5.0
print(v1 == v2) # False
print(bool(v1)) # True常用运算符魔术方法对照表:
| 运算符 | 魔术方法 | 说明 |
|---|---|---|
+ | __add__, __radd__ | 加法 |
- | __sub__, __rsub__ | 减法 |
* | __mul__, __rmul__ | 乘法 |
/ | __truediv__, __rtruediv__ | 真除法 |
// | __floordiv__, __rfloordiv__ | 整除 |
% | __mod__, __rmod__ | 取模 |
** | __pow__, __rpow__ | 幂运算 |
== | __eq__ | 相等比较 |
!= | __ne__ | 不等比较 |
< | __lt__ | 小于 |
<= | __le__ | 小于等于 |
> | __gt__ | 大于 |
>= | __ge__ | 大于等于 |
[] | __getitem__, __setitem__ | 索引访问 |
len() | __len__ | 长度 |
bool() | __bool__ | 布尔转换 |
str() | __str__ | 字符串表示 |
repr() | __repr__ | 官方字符串表示 |
2.6 语句与表达式
2.6.1 语句(Statement)
语句是执行操作的指令,不产生值:
x = 10 # 赋值语句
if x > 0: print("正数") # 条件语句
import math # 导入语句
def greet(): pass # 函数定义语句
return 42 # 返回语句2.6.2 表达式(Expression)
表达式是计算后产生值的代码:
42 # 字面量表达式
x + y # 算术表达式
"Hello" + " World" # 字符串表达式
x > 0 # 比较表达式
func() # 函数调用表达式
[x for x in range(10)] # 列表推导式表达式2.6.3 条件表达式(三元运算符)
# 语法:value_if_true if condition else value_if_false
status = "成年" if age >= 18 else "未成年"
# 等价于
if age >= 18:
status = "成年"
else:
status = "未成年"
# 嵌套使用(可读性差,不推荐)
result = "A" if score >= 90 else "B" if score >= 80 else "C"2.7 前沿技术动态
2.7.1 模式匹配(PEP 634)
Python 3.10引入结构化模式匹配,提供更强大的条件分支:
def process_command(command: tuple[str, ...]) -> str:
match command:
case ["quit"]:
return "Exiting..."
case ["load", filename]:
return f"Loading {filename}"
case ["save", filename, *options]:
opts = ", ".join(options)
return f"Saving {filename} with options: {opts}"
case ["move", source, destination] if source != destination:
return f"Moving {source} to {destination}"
case ["copy", source, destination]:
return f"Copying {source} to {destination}"
case _:
return "Unknown command"
print(process_command(("save", "data.txt", "--force", "--backup")))2.7.2 海象运算符(PEP 572)
Python 3.8引入赋值表达式,简化代码:
# 传统写法
text = input("Enter text: ")
if len(text) > 10:
print(f"Text too long: {len(text)} characters")
# 海象运算符写法
if (n := len(text := input("Enter text: "))) > 10:
print(f"Text too long: {n} characters")
# 在列表推导中使用
data = [1, 2, 3, 4, 5]
filtered = [y for x in data if (y := x * 2) > 4]2.7.3 类型系统演进
Python类型系统持续演进,提供更精确的类型表达:
from typing import TypeAlias, Self, TypeGuard
# 类型别名(Python 3.12+)
type Vector = list[float]
# Self类型(Python 3.11+)
class Builder:
def set_name(self, name: str) -> Self:
self.name = name
return self
# TypeGuard用于类型收窄
def is_string_list(val: list[object]) -> TypeGuard[list[str]]:
return all(isinstance(x, str) for x in val)2.7.4 参数语法增强
# 位置参数分隔符(Python 3.8+)
def greet(name, /, *, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Alice") # 正确
greet("Alice", greeting="Hi") # 正确
greet(name="Alice") # 错误:name是位置参数
# 参数解包增强
def func(a, b, c):
return a + b + c
args = [1, 2, 3]
kwargs = {"a": 1, "b": 2, "c": 3}
result = func(*args) # 列表解包
result = func(**kwargs) # 字典解包2.8 本章小结
本章系统介绍了Python基础语法的核心要素:
- 注释与文档:遵循PEP 257编写标准Docstring,注释解释"为什么"而非"是什么"
- 对象模型:变量是对象的引用,理解可变/不可变对象的区别是避免bug的关键
- 内存管理:引用计数是主要机制,分代GC处理循环引用,内存池优化小对象分配
- 类型系统:类型注解提升代码可维护性,mypy实现静态类型检查
- 格式化输出:f-string是现代Python的首选格式化方案
- 缩进机制:4个空格缩进是Python的语法要求,也是代码可读性的保障
- 运算符体系:掌握算术、比较、逻辑、位运算符及其优先级,理解运算符重载
- 编码规范:PEP 8是Python社区的共同约定,配合Ruff等工具自动执行
2.8.1 知识图谱
Python基础语法
├── 注释与文档
│ ├── 单行注释 (#)
│ ├── 多行注释 (""" """)
│ └── Docstring (PEP 257)
├── 变量与对象
│ ├── 对象模型 (id, type, value)
│ ├── 引用语义
│ ├── 可变/不可变对象
│ ├── 内存管理 (引用计数 + GC)
│ └── 类型注解 (Type Hints)
├── 输入输出
│ ├── print() 函数
│ ├── f-string 格式化
│ └── input() 函数
├── 缩进与代码块
│ ├── 4空格缩进
│ └── 代码块层次
└── 运算符
├── 算术运算符
├── 比较运算符
├── 逻辑运算符
├── 位运算符
├── 成员/身份运算符
└── 运算符重载2.8.2 最佳实践清单
| 场景 | 推荐做法 | 避免做法 |
|---|---|---|
| 字符串格式化 | f-string | % 格式化 |
| 值比较 | == | is |
| None检查 | x is None | x == None |
| 布尔检查 | if x: | if x == True: |
| 空容器检查 | if not lst: | if len(lst) == 0: |
| 复制列表 | lst.copy() 或 lst[:] | new = old |
| 类型注解 | 公共API必加 | 完全不加 |
| 注释 | 解释"为什么" | 重复代码内容 |
2.9 练习题
基础题
编写程序,使用f-string格式化输出你的姓名、年龄和BMI值,要求BMI保留1位小数。
编写程序,输入两个数,输出它们的和、差、积、商(整除和浮点除法)。
使用Google风格Docstring为一个函数编写文档,包含Args、Returns、Raises和Examples。
进阶题
解释以下代码的输出结果,并说明原因:
pythona = [1, 2, 3] b = a b.append(4) print(a)使用位运算实现一个简单的权限系统,支持添加、移除和检查权限。
编写一个函数,使用海象运算符简化循环中的条件判断。
项目实践
- 个人名片生成器:编写一个Python程序,要求:
- 使用input获取用户姓名、年龄、职业、邮箱
- 使用f-string格式化输出一张美观的文本名片
- 包含完整的类型注解和Docstring
- 处理输入为空的情况(使用
or提供默认值)
思考题
Python使用缩进而非花括号表示代码块,这一设计决策的利弊是什么?从软件工程角度分析其对大型项目的影响。
为什么Python中
a = b对于列表会导致"修改b影响a"的问题?这与C++的引用、Java的对象变量有何异同?is和==的区别是什么?在什么场景下应该使用is?为什么a is b对小整数返回True而对大整数可能返回False?
2.10 延伸阅读
2.10.1 Python语言规范
- PEP 8 — Style Guide for Python Code (https://peps.python.org/pep-0008/) — Python官方编码风格指南,所有Python开发者的必读文档
- PEP 257 — Docstring Conventions (https://peps.python.org/pep-0257/) — 文档字符串编写规范
- PEP 484 — Type Hints (https://peps.python.org/pep-0484/) — 类型注解的官方规范
- PEP 572 — Assignment Expressions (https://peps.python.org/pep-0572/) — 海象运算符的设计原理
2.10.2 内存管理与对象模型
- 《Python源码剖析》 (陈儒) — 深入CPython解释器实现,理解对象模型和内存管理的权威参考
- 《Fluent Python》 (Luciano Ramalho) — 第1章深入讲解Python数据模型,是理解魔术方法的最佳入门
- Python Memory Management (https://realpython.com/python-memory-management/) — Real Python的内存管理教程
- The Garbage Collector (https://devguide.python.org/internals/garbage-collector/) — Python官方开发者指南中的GC章节
2.10.3 类型系统
- 《Type-Driven Development with Idris》 (Edwin Brady) — 虽然使用Idris语言,但对理解类型驱动开发思想极有帮助
- mypy官方文档 (https://mypy.readthedocs.io/) — Python静态类型检查器的完整参考
- typing模块文档 (https://docs.python.org/3/library/typing.html) — Python标准库类型系统文档
2.10.4 代码风格工具
- Ruff (https://docs.astral.sh/ruff/) — 现代Python代码检查和格式化工具,速度比传统工具快10-100倍
- Black (https://black.readthedocs.io/) — 不妥协的Python代码格式化器
- isort (https://pycqa.github.io/isort/) — import语句自动排序工具
- pre-commit (https://pre-commit.com/) — Git钩子框架,自动执行代码检查
下一章:第3章 数据类型