怎样让Python案例更Pythonic

wen python案例 50

本文目录导读:

怎样让Python案例更Pythonic

  1. 用列表推导式替换显式循环
  2. 用enumerate获取索引,避免手动计数
  3. 用zip并行遍历多个序列
  4. 用in检查成员关系
  5. 用with管理资源(文件、锁等)
  6. 用字典/集合做去重、计数
  7. 用any/all代替显式循环判断
  8. 用装饰器分离横切关注点
  9. 用unpacking替代索引访问
  10. 用匹配语句替代长串if-elif
  11. 判断代码是否Pythonic的标准

让Python案例更“Pythonic”的核心是:使用Python惯用写法、充分利用语言特性、追求代码的简洁与可读性,下面从几个维度给出具体方法和示例。


用列表推导式替换显式循环

不Pythonic

squares = []
for i in range(10):
    squares.append(i * i)

Pythonic

squares = [i * i for i in range(10)]

适用场景:创建新列表、过滤数据、简单变换。


用enumerate获取索引,避免手动计数

不Pythonic

i = 0
for item in items:
    print(i, item)
    i += 1

Pythonic

for i, item in enumerate(items):
    print(i, item)

进阶:可指定起始索引 enumerate(items, start=1)


用zip并行遍历多个序列

不Pythonic

for i in range(len(names)):
    print(names[i], ages[i])

Pythonic

for name, age in zip(names, ages):
    print(name, age)

用in检查成员关系

不Pythonic

if name in names_list:

但避免if names_list.count(name) > 0(效率低且啰嗦)。


用with管理资源(文件、锁等)

不Pythonic

f = open('file.txt', 'r')
try:
    content = f.read()
finally:
    f.close()

Pythonic

with open('file.txt', 'r') as f:
    content = f.read()

用字典/集合做去重、计数

不Pythonic(手动计数)

counts = {}
for word in words:
    if word in counts:
        counts[word] += 1
    else:
        counts[word] = 1

Pythonic(使用defaultdict或Counter)

from collections import Counter
counts = Counter(words)

或:

from collections import defaultdict
counts = defaultdict(int)
for word in words:
    counts[word] += 1

用any/all代替显式循环判断

不Pythonic

result = False
for num in nums:
    if num > 10:
        result = True
        break

Pythonic

result = any(num > 10 for num in nums)

用装饰器分离横切关注点

不Pythonic(内嵌计时逻辑)

def process_data():
    import time
    start = time.time()
    # 实际逻辑
    print(f"耗时: {time.time()-start}")

Pythonic

import time
from functools import wraps
def timer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"{func.__name__} 耗时: {time.time()-start:.3f}s")
        return result
    return wrapper
@timer
def process_data():
    # 原始逻辑,无杂质
    pass

用unpacking替代索引访问

不Pythonic

first = items[0]
second = items[1]

Pythonic

first, second = items[0], items[1]  # 仍然不够好
# 更好的:
first, second, *rest = items

通用解包

a, b, *c = [1, 2, 3, 4, 5]  # a=1, b=2, c=[3,4,5]

用匹配语句替代长串if-elif

Python 3.10+ 可用:

不Pythonic

if status == 200:
    handle_ok()
elif status == 404:
    handle_not_found()
elif status == 500:
    handle_server_error()
else:
    handle_unknown()

Pythonic

match status:
    case 200:
        handle_ok()
    case 404:
        handle_not_found()
    case 500:
        handle_server_error()
    case _:
        handle_unknown()

判断代码是否Pythonic的标准

  1. 可读性优先(代码即文档)
  2. 充分利用标准库(itertools, functools, collections等)
  3. 遵循PEP 8(命名、缩进、空行)
  4. 尽量少写"模式代码"(样板代码是异味)
  5. 追求表达力(一行完成而非三层嵌套)

快速自查表

  • 是否用了 range(len(...)) ? → 改为 enumeratezip
  • 是否手动维护索引变量? → 改为 enumerate
  • 是否用 for i in range(len(a)) 遍历两个列表? → 改为 zip
  • 是否用 try/finally 管理资源? → 改为 with
  • 是否有多层嵌套的列表处理? → 考虑列表推导式加条件

一个实际案例的前后对比

原始(不Pythonic)

result = []
for i in range(len(data)):
    if data[i] > 0:
        result.append(data[i] * 2)

Pythonic

result = [x * 2 for x in data if x > 0]

这样改后,不仅更短,而且变量名 xdata[i] 更清晰,意图一目了然。

抱歉,评论功能暂时关闭!