No history yet

Pythonic 编程风格

Pythonic 之道

你已经掌握了编程的基本功,比如变量和循环。现在,我们来探讨如何用更地道、更优雅的方式编写 Python 代码。这不仅仅是让代码能跑起来,更是关于如何写出清晰、简洁且易于阅读的代码,这就是所谓的 “Pythonic” 风格。

“代码的阅读次数远多于编写次数。” Pythonic 的核心正是为了提高代码的可读性。

Python 提供了许多独特的语法和工具,可以让你用更少的代码完成更多的工作。掌握这些,你的代码会变得更强大,也会让你更享受编程的过程。

用推导式浓缩循环

你肯定写过这样的 for 循环:创建一个空列表,然后通过循环向其中添加元素。虽然这能行得通,但 Python 提供了更简洁的方案:推导式 (Comprehensions)。

假设我们想创建一个包含 0 到 9 平方的列表。传统的写法是这样的:

squares = []
for i in range(10):
    squares.append(i * i)
# squares -> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

使用列表推导式,我们可以把这四行代码压缩成一行,而且意思表达得更直接:“为 0 到 9 的每个 i,创建一个 i 的平方,并放入新列表。”

squares = [i * i for i in range(10)]
# squares -> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

这种语法不仅限于列表。你也可以用它来创建字典和集合。例如,创建一个将数字映射到其平方的字典:

# 字典推导式
number_to_square = {i: i * i for i in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# 集合推导式 (注意结果中没有重复项)
unique_squares = {i % 3 for i in range(10)}
# {0, 1, 2}

推导式还可以加入条件判断。比如,我们只想计算偶数的平方:

even_squares = [i * i for i in range(10) if i % 2 == 0]
# [0, 4, 16, 36, 64]

优雅地迭代

在其他语言中,遍历一个列表并需要索引时,你可能会写出类似 C 风格的循环。这种方式在 Python 中是完全不必要的,而且显得很笨拙。

items = ["apple", "banana", "cherry"]
# 不推荐的 C 风格
for i in range(len(items)):
    print(f"{i}: {items[i]}")

Python 提供了内置函数 enumerate 来解决这个问题。它会在每次迭代时,同时返回索引和对应的值,让代码更清晰。

items = ["apple", "banana", "cherry"]
# Pythonic 的方式
for i, item in enumerate(items):
    print(f"{i}: {item}")

另一个常见场景是需要同时遍历多个列表。新手可能会用索引来操作,但这很容易出错。正确的做法是使用 zip 函数,它能像拉链一样将多个可迭代对象“压缩”在一起。

students = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]

# Pythonic 的方式
for student, score in zip(students, scores):
    print(f"{student}'s score is {score}")

注意,zip 会在最短的那个列表耗尽时停止。这通常是你想要的行为,但也需要留意。

切片和真值测试

切片 (slicing) 是 Python 处理序列的强大工具。你不仅可以用它来获取子列表,还可以用它来修改、反转甚至复制列表。

numbers = [0, 1, 2, 3, 4, 5, 6, 7]

# 获取索引 24 的元素 (不包括 5)
print(numbers[2:5]) # [2, 3, 4]

# 获取从开头到索引 2 的元素 (不包括 3)
print(numbers[:3]) # [0, 1, 2]

# 获取从索引 5 到结尾的元素
print(numbers[5:]) # [5, 6, 7]

# 使用负数索引从末尾开始计数
print(numbers[-3:]) # [5, 6, 7]

切片还有一个高级用法,就是带有“步长”的扩展切片。list[start:stop:step]。这让反转序列变得异常简单。

numbers = [0, 1, 2, 3, 4, 5, 6, 7]

# 获取所有偶数位置的元素
print(numbers[::2]) # [0, 2, 4, 6]

# 反转列表
print(numbers[::-1]) # [7, 6, 5, 4, 3, 2, 1]

接下来是真值测试 (Truth Value Testing)。在 Python 中,你不需要显式地检查一个列表是否为空,或者一个数值是否为零。Python 有一套简单的规则来判断对象的“真假”。

  • 数字 00.0 被认为是 False,其他数字为 True
  • 空的字符串 ""、列表 []、字典 {}、集合 set() 等空容器被认为是 False
  • None 对象永远是 False

利用这一点,你的条件判断可以写得更简洁。

my_list = []

# 不推荐
if len(my_list) == 0:
    print("List is empty.")

# 推荐的 Pythonic 方式
if not my_list:
    print("List is empty.")

Python 之禅

Python 的设计哲学被总结为“Python 之禅”。它不是严格的规则,而是一系列指导原则,帮助你写出更好的代码。你可以在任何 Python 解释器中输入 import this 来看到它。

优美胜于丑陋 (Beautiful is better than ugly) 明了胜于晦涩 (Explicit is better than implicit) 简单胜于复杂 (Simple is better than complex) 扁平胜于嵌套 (Flat is better than nested) 可读性很重要 (Readability counts)

这些原则正是我们刚刚讨论的所有技巧的根基。无论是用推导式代替循环,还是用 enumerate 简化迭代,目标都是让代码更简单、更明确、更易读。当你犹豫不决时,问问自己:哪种写法更符合这些原则?这通常就是更 Pythonic 的选择。

Quiz Questions 1/6

以下哪段代码能以最 Pythonic 的方式,创建一个包含 0 到 4 的每个数字的平方的列表?

Quiz Questions 2/6

在 Python 中,当需要同时遍历一个列表的索引和对应的值时,最佳实践是使用哪个内置函数?

遵循这些原则,你的代码会自然而然地变得更优雅、高效。这就是 Pythonic 编程的魅力所在。