第2章 基础语法

学习目标

完成本章学习后,读者将能够:

  • 掌握Python注释的编写规范与文档字符串(Docstring)标准
  • 理解Python变量模型的本质——引用语义与对象模型
  • 熟练运用f-string等格式化方法进行专业级输出
  • 理解Python缩进机制的设计原理与工程意义
  • 遵循PEP 8规范编写符合行业标准的代码

2.1 注释与文档

2.1.1 单行注释

Python使用#标记单行注释,解释器会忽略从#到行末的所有内容:

1
2
3
# 计算圆的面积
radius = 5
area = 3.14159 * radius ** 2 # 面积公式:S = πr²

2.1.2 多行注释与文档字符串

Python没有真正的多行注释语法。三引号字符串("""''')在模块/类/函数级别会成为文档字符串(Docstring),而非注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
"""
模块级文档字符串

描述整个模块的功能、作者、版本等信息。
可通过 __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 注释最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 好的注释:解释"为什么"(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中变量是对象的引用(标签),而非存储值的容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
C语言模型:                Python模型:
┌──────┐ name ──┐
│ name │──→ 42 age ──┤
└──────┘ │
┌─────┐ ┌──────┴──────┐
│ age │──→ 25 │ int(42) │
└─────┘ │ id: 1407... │
│ value: 42 │
│ type: int │
└─────────────┘
┌─────────────┐
│ int(25) │
│ id: 1407... │
│ value: 25 │
│ type: int │
└─────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
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}原地修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 不可变对象:修改创建新对象
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关键字
  • 区分大小写
1
2
3
4
5
6
7
8
9
10
11
# 合法命名
name = "Alice"
user_name = "Bob"
_user = "David"
user2 = "Eve"
π = 3.14159 # Unicode标识符(不推荐)

# 非法命名
2user = "Alice" # 不能以数字开头
user-name = "Bob" # 不能包含连字符
class = "Math" # 不能使用关键字

PEP 8命名约定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 变量和函数: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):
pass

2.2.4 赋值语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 基本赋值
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 变量删除

1
2
3
4
5
6
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主要使用引用计数来管理内存,每个对象维护一个引用计数器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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使用分代垃圾回收器处理这类情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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)优化小对象的分配:

1
2
3
4
5
6
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提供了丰富的内省能力,这是动态语言的核心特性之一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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模块进行深度内省:

1
2
3
4
5
6
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),支持静态类型检查:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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")

类型检查工具:

1
2
pip install mypy
mypy your_script.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from 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函数详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 基本输出
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最现代、最高效的字符串格式化方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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 = 00101010

format方法

1
2
3
4
5
6
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))

%格式化(旧式,仅作了解)

1
2
print("姓名:%s,年龄:%d" % ("Alice", 25))
print("π ≈ %.2f" % 3.14159)

工程实践:新项目统一使用f-string。format方法仅在需要动态模板时使用。%格式化已不推荐。

2.3.3 input函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 基本输入
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最具争议也最具特色的设计决策:

1
2
3
4
5
if True:
print("缩进4个空格") # 属于if代码块
if True:
print("缩进8个空格") # 属于嵌套if代码块
print("回到顶层") # 不属于任何代码块

设计哲学:Guido van Rossum选择缩进语法的原因是——代码被阅读的次数远多于编写的次数,强制缩进消除了代码格式不一致的问题,使Python代码天然具有良好的可读性。这一设计在大型项目中显著降低了代码审查的认知负担。

2.4.2 缩进规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 规则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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 错误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 算术运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 1

2.5.2 比较运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 逻辑运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 位运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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比较
10not逻辑非
11and逻辑与
12or逻辑或
13if-else条件表达式

工程实践:不要依赖运算符优先级,复杂表达式使用括号明确意图。2 + 3 * 4 应写为 2 + (3 * 4)

2.5.6 成员运算符与身份运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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允许通过魔术方法重载运算符,实现自定义类型的行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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)

语句是执行操作的指令,不产生值:

1
2
3
4
5
x = 10                    # 赋值语句
if x > 0: print("正数") # 条件语句
import math # 导入语句
def greet(): pass # 函数定义语句
return 42 # 返回语句

2.6.2 表达式(Expression)

表达式是计算后产生值的代码:

1
2
3
4
5
6
42                        # 字面量表达式
x + y # 算术表达式
"Hello" + " World" # 字符串表达式
x > 0 # 比较表达式
func() # 函数调用表达式
[x for x in range(10)] # 列表推导式表达式

2.6.3 条件表达式(三元运算符)

1
2
3
4
5
6
7
8
9
10
11
# 语法: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引入结构化模式匹配,提供更强大的条件分支:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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引入赋值表达式,简化代码:

1
2
3
4
5
6
7
8
9
10
11
12
# 传统写法
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类型系统持续演进,提供更精确的类型表达:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 参数语法增强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 位置参数分隔符(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基础语法的核心要素:

  1. 注释与文档:遵循PEP 257编写标准Docstring,注释解释”为什么”而非”是什么”
  2. 对象模型:变量是对象的引用,理解可变/不可变对象的区别是避免bug的关键
  3. 内存管理:引用计数是主要机制,分代GC处理循环引用,内存池优化小对象分配
  4. 类型系统:类型注解提升代码可维护性,mypy实现静态类型检查
  5. 格式化输出:f-string是现代Python的首选格式化方案
  6. 缩进机制:4个空格缩进是Python的语法要求,也是代码可读性的保障
  7. 运算符体系:掌握算术、比较、逻辑、位运算符及其优先级,理解运算符重载
  8. 编码规范:PEP 8是Python社区的共同约定,配合Ruff等工具自动执行

2.8.1 知识图谱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Python基础语法
├── 注释与文档
│ ├── 单行注释 (#)
│ ├── 多行注释 (""" """)
│ └── Docstring (PEP 257)
├── 变量与对象
│ ├── 对象模型 (id, type, value)
│ ├── 引用语义
│ ├── 可变/不可变对象
│ ├── 内存管理 (引用计数 + GC)
│ └── 类型注解 (Type Hints)
├── 输入输出
│ ├── print() 函数
│ ├── f-string 格式化
│ └── input() 函数
├── 缩进与代码块
│ ├── 4空格缩进
│ └── 代码块层次
└── 运算符
├── 算术运算符
├── 比较运算符
├── 逻辑运算符
├── 位运算符
├── 成员/身份运算符
└── 运算符重载

2.8.2 最佳实践清单

场景推荐做法避免做法
字符串格式化f-string% 格式化
值比较==is
None检查x is Nonex == None
布尔检查if x:if x == True:
空容器检查if not lst:if len(lst) == 0:
复制列表lst.copy()lst[:]new = old
类型注解公共API必加完全不加
注释解释”为什么”重复代码内容

2.9 练习题

基础题

  1. 编写程序,使用f-string格式化输出你的姓名、年龄和BMI值,要求BMI保留1位小数。

  2. 编写程序,输入两个数,输出它们的和、差、积、商(整除和浮点除法)。

  3. 使用Google风格Docstring为一个函数编写文档,包含Args、Returns、Raises和Examples。

进阶题

  1. 解释以下代码的输出结果,并说明原因:

    1
    2
    3
    4
    a = [1, 2, 3]
    b = a
    b.append(4)
    print(a)
  2. 使用位运算实现一个简单的权限系统,支持添加、移除和检查权限。

  3. 编写一个函数,使用海象运算符简化循环中的条件判断。

项目实践

  1. 个人名片生成器:编写一个Python程序,要求:
    • 使用input获取用户姓名、年龄、职业、邮箱
    • 使用f-string格式化输出一张美观的文本名片
    • 包含完整的类型注解和Docstring
    • 处理输入为空的情况(使用or提供默认值)

思考题

  1. Python使用缩进而非花括号表示代码块,这一设计决策的利弊是什么?从软件工程角度分析其对大型项目的影响。

  2. 为什么Python中a = b对于列表会导致”修改b影响a”的问题?这与C++的引用、Java的对象变量有何异同?

  3. is==的区别是什么?在什么场景下应该使用is?为什么a is b对小整数返回True而对大整数可能返回False?

2.10 延伸阅读

2.10.1 Python语言规范

2.10.2 内存管理与对象模型

2.10.3 类型系统

2.10.4 代码风格工具


下一章:第3章 数据类型