19 - Pythonic 写法: 地道的Python代码

3 阅读19分钟

想系统提升编程能力、查看更完整的学习路线,欢迎访问 AI Compass:github.com/tingaicompa… 仓库持续更新刷题题解、Python 基础和 AI 实战内容,适合想高效进阶的你。

19 - Pythonic 写法: 地道的Python代码

学习目标: 掌握Pythonic编程风格,写出优雅、高效、可读性强的Python代码


💡 什么是 Pythonic?

"Pythonic" 是指遵循 Python 社区的编程风格和最佳实践,充分利用 Python 的语言特性,写出简洁、优雅、高效的代码。

核心理念: The Zen of Python (在终端输入 import this 查看)

  • 优美胜于丑陋
  • 明了胜于晦涩
  • 简洁胜于复杂
  • 可读性很重要

📊 快速参考表

场景❌ 不够 Pythonic✅ Pythonic说明
变量交换temp=a; a=b; b=tempa, b = b, a序列解包
列表反转for i in range(len(a)-1,-1,-1)a[::-1]切片
遍历列表for i in range(len(a))for i, v in enumerate(a)enumerate
并行遍历for i in range(len(a))for x, y in zip(a, b)zip
列表构建for x in a: result.append(f(x))[f(x) for x in a]列表推导式
条件表达式if x>0: r="正" else: r="负"r = "正" if x>0 else "负"三元表达式
默认值if v is None: v=[]v = v or []or 短路
字符串拼接for w in words: s+=w"".join(words)join
文件读取f=open(); f.read(); f.close()with open() as f: f.read()with
检查存在found=False; for x in a: if x==t: found=Truet in ain
字典取值d["key"]d.get("key", default)get
列表去重for x in a: if x not in r: r.append(x)list(set(a))set
多条件if x==1 or x==2 or x==3if x in (1,2,3)in
范围判断if x>0 and x<10if 0<x<10链式比较
字典合并for k,v in d2.items(): d1[k]=vd1 | d2 (3.9+)字典运算符
列表展平for row in m: for x in row: r.append(x)[x for row in m for x in row]推导式
函数解包f(a[0], a[1], a[2])f(*a)* 解包
任意满足for x in a: if cond(x): found=True; breakany(cond(x) for x in a)any
全部满足for x in a: if not cond(x): ok=False; breakall(cond(x) for x in a)all
空值检查if len(a)==0if not a真值测试
频率统计for x in a: d[x]=d.get(x,0)+1Counter(a)Counter
最大K个sorted(a)[-k:]heapq.nlargest(k, a)heapq
二分查找手动实现bisect.bisect_left(a, x)bisect
格式化"Name: "+name+", Age: "+str(age)f"Name: {name}, Age: {age}"f-string

💻 Pythonic 代码示例

1. 变量交换

# ❌ 不够Pythonic (使用临时变量)
temp = a
a = b
b = temp

# ✅ Pythonic (元组解包)
a, b = b, a

2. 列表/字符串反转

# ❌ 不够Pythonic
result = []
for i in range(len(arr)-1, -1, -1):
    result.append(arr[i])

# ✅ Pythonic (切片)
result = arr[::-1]
s = s[::-1]  # 字符串反转

3. 遍历列表

nums = [10, 20, 30]

# ❌ 不够Pythonic (使用索引)
for i in range(len(nums)):
    print(i, nums[i])

# ✅ Pythonic (使用enumerate)
for i, num in enumerate(nums):
    print(i, num)

4. 同时遍历多个列表

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

# ❌ 不够Pythonic
for i in range(len(names)):
    print(names[i], scores[i])

# ✅ Pythonic (使用zip)
for name, score in zip(names, scores):
    print(name, score)

5. 列表构建

# ❌ 不够Pythonic
squares = []
for i in range(10):
    if i % 2 == 0:
        squares.append(i ** 2)

# ✅ Pythonic (列表推导式)
squares = [i ** 2 for i in range(10) if i % 2 == 0]

6. 条件表达式

# ❌ 不够Pythonic
if x > 0:
    result = "正数"
else:
    result = "非正数"

# ✅ Pythonic (三元表达式)
result = "正数" if x > 0 else "非正数"

7. 默认值处理

# ❌ 不够Pythonic
if value is None:
    value = []

# ✅ Pythonic (使用or)
value = value or []

# ✅ 更好 (避免0、False等假值的问题)
value = value if value is not None else []

8. 字符串拼接

words = ["Python", "is", "awesome"]

# ❌ 不够Pythonic (循环拼接,效率低)
result = ""
for word in words:
    result += word + " "

# ✅ Pythonic (使用join)
result = " ".join(words)

9. 文件读取

# ❌ 不够Pythonic
f = open("file.txt")
content = f.read()
f.close()

# ✅ Pythonic (使用with,自动关闭)
with open("file.txt") as f:
    content = f.read()

10. 检查元素是否存在

# ❌ 不够Pythonic
found = False
for item in items:
    if item == target:
        found = True
        break

# ✅ Pythonic (使用in)
found = target in items

11. 获取字典值

d = {"name": "Alice", "age": 20}

# ❌ 可能抛出KeyError
value = d["city"]

# ✅ Pythonic (使用get,提供默认值)
value = d.get("city", "Unknown")

12. 列表去重

nums = [1, 2, 2, 3, 1, 4]

# ❌ 不够Pythonic
result = []
for num in nums:
    if num not in result:
        result.append(num)

# ✅ Pythonic (使用set)
result = list(set(nums))

# ✅ 更好 (保持原始顺序)
result = list(dict.fromkeys(nums))

13. 多条件判断

# ❌ 不够Pythonic
if x == 1 or x == 2 or x == 3:
    print("找到了")

# ✅ Pythonic (使用in)
if x in (1, 2, 3):
    print("找到了")

# ✅ 范围判断
if 0 <= x < 10:
    print("在范围内")

14. 字典合并

d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}

# ✅ Pythonic (Python 3.9+)
merged = d1 | d2

# ✅ Pythonic (Python 3.5+)
merged = {**d1, **d2}

15. 链式比较

x = 5

# ❌ 不够Pythonic
if x > 0 and x < 10:
    print("在范围内")

# ✅ Pythonic (链式比较)
if 0 < x < 10:
    print("在范围内")

16. 列表展平

matrix = [[1, 2], [3, 4], [5, 6]]

# ❌ 不够Pythonic
result = []
for row in matrix:
    for num in row:
        result.append(num)

# ✅ Pythonic (列表推导式)
result = [num for row in matrix for num in row]

17. 函数参数解包

def add(a, b, c):
    return a + b + c

nums = [1, 2, 3]

# ❌ 不够Pythonic
result = add(nums[0], nums[1], nums[2])

# ✅ Pythonic (使用*解包)
result = add(*nums)

18. 使用any()和all()

nums = [1, 2, 3, 4, 5]

# ❌ 不够Pythonic
has_even = False
for num in nums:
    if num % 2 == 0:
        has_even = True
        break

# ✅ Pythonic (使用any)
has_even = any(num % 2 == 0 for num in nums)

# ✅ 检查是否全部满足条件
all_positive = all(num > 0 for num in nums)

19. 空值检查

nums = []

# ❌ 不够Pythonic
if len(nums) == 0:
    print("空列表")

# ✅ Pythonic (利用真值测试)
if not nums:
    print("空列表")

# 非空检查
if nums:
    print("非空")

20. 多个返回值

# ✅ Pythonic (返回元组)
def get_user_info():
    return "Alice", 20, "Beijing"

name, age, city = get_user_info()

# 忽略不需要的值
name, _, city = get_user_info()

21. 字符串格式化

name = "Alice"
age = 20

# ❌ 不够Pythonic (字符串拼接)
result = "Name: " + name + ", Age: " + str(age)

# ✅ Pythonic (f-string, Python 3.6+, 最推荐)
result = f"Name: {name}, Age: {age}"

# ✅ Pythonic (format 方法)
result = "Name: {}, Age: {}".format(name, age)
result = "Name: {n}, Age: {a}".format(n=name, a=age)

# f-string 的高级用法
price = 123.456
print(f"Price: {price:.2f}")  # Price: 123.46

nums = [1, 2, 3]
print(f"Sum: {sum(nums)}")    # 可以包含表达式

22. reversed() 倒序遍历

nums = [1, 2, 3, 4, 5]

# ❌ 不够Pythonic
for i in range(len(nums)-1, -1, -1):
    print(nums[i])

# ✅ Pythonic (reversed)
for num in reversed(nums):
    print(num)

# ✅ enumerate + reversed
for i, num in enumerate(reversed(nums)):
    print(i, num)

23. is vs == 的区别

# == 比较值是否相等
# is 比较是否是同一个对象(内存地址)

# ✅ Pythonic (None, True, False 使用 is)
if x is None:
    print("x is None")

if flag is True:
    print("flag is True")

# ❌ 不推荐
if x == None:
    pass

# ✅ 其他情况使用 ==
if name == "Alice":
    pass

24. extend vs append

nums = [1, 2, 3]

# append: 添加单个元素(可以是列表)
nums.append([4, 5])
print(nums)  # [1, 2, 3, [4, 5]]

nums = [1, 2, 3]
# ✅ extend: 扩展多个元素
nums.extend([4, 5])
print(nums)  # [1, 2, 3, 4, 5]

# ✅ 更Pythonic (使用+=)
nums += [6, 7]
print(nums)  # [1, 2, 3, 4, 5, 6, 7]

25. 切片赋值

nums = [1, 2, 3, 4, 5]

# ✅ Pythonic (切片赋值)
nums[1:3] = [20, 30]
print(nums)  # [1, 20, 30, 4, 5]

# 插入多个元素
nums[2:2] = [100, 200]
print(nums)  # [1, 20, 100, 200, 30, 4, 5]

# 删除多个元素
nums[1:3] = []
print(nums)  # [1, 200, 30, 4, 5]

26. sorted 的高级用法

# 多关键字排序
students = [
    ("Alice", 20, 85),
    ("Bob", 19, 92),
    ("Charlie", 20, 78)
]

# ✅ 按年龄升序,成绩降序
sorted_students = sorted(students, key=lambda x: (x[1], -x[2]))

# ✅ 使用 operator.itemgetter (更快)
from operator import itemgetter
sorted_students = sorted(students, key=itemgetter(1, 2))

# ✅ 倒序
sorted_students = sorted(students, key=itemgetter(2), reverse=True)

27. min/max 的 key 参数

words = ["apple", "banana", "cherry", "date"]

# ❌ 不够Pythonic
longest = ""
for word in words:
    if len(word) > len(longest):
        longest = word

# ✅ Pythonic (max with key)
longest = max(words, key=len)

# ✅ 找到字典中值最大的键
scores = {"Alice": 85, "Bob": 92, "Charlie": 78}
best_student = max(scores, key=scores.get)
print(best_student)  # Bob

28. 字典推导式高级用法

# ✅ 过滤和转换
nums = [1, 2, 3, 4, 5]
square_dict = {n: n**2 for n in nums if n % 2 == 0}
print(square_dict)  # {2: 4, 4: 16}

# ✅ 从两个列表构建字典
keys = ["a", "b", "c"]
values = [1, 2, 3]
d = dict(zip(keys, values))
# 或使用推导式
d = {k: v for k, v in zip(keys, values)}

29. 集合运算

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

# ✅ Pythonic (集合运算)
union = a | b          # 并集: {1, 2, 3, 4, 5, 6}
intersection = a & b   # 交集: {3, 4}
difference = a - b     # 差集: {1, 2}
sym_diff = a ^ b       # 对称差: {1, 2, 5, 6}

# 判断子集/超集
is_subset = {1, 2} <= a
is_superset = a >= {1, 2}

30. 统计和分组

from collections import Counter

# ✅ Counter 统计频率
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
counter = Counter(words)
print(counter)  # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
print(counter.most_common(2))  # [('apple', 3), ('banana', 2)]

# ✅ 字符串字符统计
s = "hello world"
char_count = Counter(s)
print(char_count)  # Counter({'l': 3, 'o': 2, ...})

🎯 在算法题中的应用

1. 链表反转 (序列解包)

def reverseList(head):
    prev, curr = None, head
    while curr:
        curr.next, prev, curr = prev, curr, curr.next
    return prev

2. 两数之和 (enumerate + 字典)

def twoSum(nums, target):
    seen = {}
    for i, num in enumerate(nums):
        complement = target - num
        if complement in seen:
            return [seen[complement], i]
        seen[num] = i

3. 最大子数组和 (链式赋值)

def maxSubArray(nums):
    max_sum = curr_sum = nums[0]
    for num in nums[1:]:
        curr_sum = max(num, curr_sum + num)
        max_sum = max(max_sum, curr_sum)
    return max_sum

4. 有效的括号 (栈 + in)

def isValid(s):
    stack = []
    pairs = {'(': ')', '[': ']', '{': '}'}

    for char in s:
        if char in pairs:
            stack.append(char)
        elif not stack or pairs[stack.pop()] != char:
            return False

    return not stack

5. 字母异位词 (sorted + Counter)

from collections import Counter

def isAnagram(s, t):
    return Counter(s) == Counter(t)
    # 或者
    return sorted(s) == sorted(t)

6. 合并区间 (lambda排序)

def merge(intervals):
    intervals.sort(key=lambda x: x[0])
    result = [intervals[0]]

    for start, end in intervals[1:]:
        if start <= result[-1][1]:
            result[-1][1] = max(result[-1][1], end)
        else:
            result.append([start, end])

    return result

7. 滑动窗口最大值 (双端队列)

from collections import deque

def maxSlidingWindow(nums, k):
    dq = deque()
    result = []

    for i, num in enumerate(nums):
        # 移除超出窗口的元素
        if dq and dq[0] < i - k + 1:
            dq.popleft()

        # 维护递减队列
        while dq and nums[dq[-1]] < num:
            dq.pop()

        dq.append(i)

        # 窗口形成后开始记录结果
        if i >= k - 1:
            result.append(nums[dq[0]])

    return result

8. 分组字母异位词 (defaultdict)

from collections import defaultdict

def groupAnagrams(strs):
    groups = defaultdict(list)
    for s in strs:
        key = ''.join(sorted(s))
        groups[key].append(s)
    return list(groups.values())

# 使用
print(groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"]))
# [['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]

9. 前K个高频元素 (Counter + heapq)

from collections import Counter
import heapq

def topKFrequent(nums, k):
    # ✅ Pythonic: Counter统计 + most_common
    return [num for num, _ in Counter(nums).most_common(k)]

# 或使用 heapq.nlargest
def topKFrequent2(nums, k):
    count = Counter(nums)
    return heapq.nlargest(k, count.keys(), key=count.get)

10. 斐波那契数列 (lru_cache 缓存)

from functools import lru_cache

# ✅ Pythonic: 使用缓存避免重复计算
@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

print(fib(100))  # 秒出结果

11. 子集生成 (itertools.combinations)

from itertools import combinations, chain

def subsets(nums):
    # ✅ Pythonic: 使用 combinations 生成所有子集
    return list(chain.from_iterable(
        combinations(nums, r) for r in range(len(nums) + 1)
    ))

print(subsets([1, 2, 3]))
# [(), (1,), (2,), (3,), (1,2), (1,3), (2,3), (1,2,3)]

12. 寻找第K大元素 (heapq.nlargest)

import heapq

def findKthLargest(nums, k):
    # ✅ Pythonic: 一行代码
    return heapq.nlargest(k, nums)[-1]

13. 单词模式匹配 (zip + set)

def wordPattern(pattern, s):
    words = s.split()
    # ✅ Pythonic: 使用 zip 和 set 检查一一对应关系
    return (len(pattern) == len(words) and
            len(set(zip(pattern, words))) == len(set(pattern)) == len(set(words)))

print(wordPattern("abba", "dog cat cat dog"))  # True
print(wordPattern("abba", "dog cat cat fish")) # False

14. 移除重复元素 (海象运算符)

def removeDuplicates(nums):
    # ✅ Pythonic: 使用海象运算符 (Python 3.8+)
    seen = set()
    return [x for x in nums if x not in seen and not seen.add(x)]

# 注意: set.add() 返回 None (假值), not None 为 True

15. 区间合并 (sorted + 生成器)

def merge(intervals):
    # ✅ Pythonic: sorted + 生成器
    intervals = sorted(intervals, key=lambda x: x[0])

    def merge_intervals():
        current = intervals[0]
        for interval in intervals[1:]:
            if interval[0] <= current[1]:
                current[1] = max(current[1], interval[1])
            else:
                yield current
                current = interval
        yield current

    return list(merge_intervals())

🔥 高级Pythonic技巧

1. 生成器表达式与生成器函数

# 生成器表达式 (按需生成,节省内存)
squares = (x**2 for x in range(1000000))

# ✅ 生成器函数 (yield)
def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

# 使用生成器
for num in fibonacci(10):
    print(num)  # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34

# ✅ 生成器可以节省内存
# 读取大文件
def read_large_file(file_path):
    with open(file_path) as f:
        for line in f:  # 逐行读取,不会一次性加载到内存
            yield line.strip()

2. 海象运算符 := (Python 3.8+)

# ❌ 不够Pythonic
match = re.search(pattern, text)
if match:
    print(match.group(1))

# ✅ Pythonic (海象运算符)
if match := re.search(pattern, text):
    print(match.group(1))

# ✅ 在列表推导式中使用
# 只计算一次复杂表达式
results = [y for x in data if (y := process(x)) > threshold]

# ✅ while 循环中
while (line := f.readline()):
    process(line)

3. 字典的 setdefault 和 defaultdict

# ❌ 不够Pythonic
if key not in d:
    d[key] = []
d[key].append(value)

# ✅ Pythonic (setdefault)
d.setdefault(key, []).append(value)

# ✅ 更好 (defaultdict)
from collections import defaultdict
d = defaultdict(list)
d[key].append(value)  # 不需要检查key是否存在

# ✅ defaultdict 的其他用法
# 计数
counter = defaultdict(int)
for item in items:
    counter[item] += 1

# 分组
groups = defaultdict(list)
for item in items:
    groups[item.category].append(item)

4. functools 常用工具

from functools import lru_cache, reduce, partial

# ✅ lru_cache: 缓存函数结果
@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# ✅ reduce: 累积操作
from operator import add
total = reduce(add, [1, 2, 3, 4, 5])  # 15
# 等价于 sum([1, 2, 3, 4, 5])

# ✅ partial: 部分应用函数
def power(base, exp):
    return base ** exp

square = partial(power, exp=2)
cube = partial(power, exp=3)

print(square(5))  # 25
print(cube(3))    # 27

5. operator 模块 (替代 lambda)

from operator import itemgetter, attrgetter, methodcaller

# ✅ itemgetter (比 lambda 更快)
students = [("Alice", 85), ("Bob", 92), ("Charlie", 78)]

# lambda 方式
sorted_students = sorted(students, key=lambda x: x[1])

# ✅ itemgetter 方式 (更快,更清晰)
sorted_students = sorted(students, key=itemgetter(1))

# ✅ 多个键排序
sorted_students = sorted(students, key=itemgetter(1, 0))

# ✅ attrgetter (获取对象属性)
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score

students = [Student("Alice", 85), Student("Bob", 92)]
sorted_students = sorted(students, key=attrgetter('score'))

# ✅ methodcaller (调用对象方法)
upper_list = list(map(methodcaller('upper'), ['hello', 'world']))
# ['HELLO', 'WORLD']

6. itertools 强大工具

from itertools import (
    chain, combinations, permutations, product,
    groupby, accumulate, islice, cycle, repeat
)

# ✅ chain: 连接多个可迭代对象
list(chain([1, 2], [3, 4], [5]))  # [1, 2, 3, 4, 5]

# ✅ combinations: 组合
list(combinations([1, 2, 3], 2))  # [(1,2), (1,3), (2,3)]

# ✅ permutations: 排列
list(permutations([1, 2, 3], 2))  # [(1,2), (1,3), (2,1), (2,3), (3,1), (3,2)]

# ✅ product: 笛卡尔积
list(product([1, 2], ['a', 'b']))  # [(1,'a'), (1,'b'), (2,'a'), (2,'b')]

# ✅ groupby: 分组
data = [('A', 1), ('A', 2), ('B', 3), ('B', 4)]
for key, group in groupby(data, key=lambda x: x[0]):
    print(key, list(group))
# A [('A', 1), ('A', 2)]
# B [('B', 3), ('B', 4)]

# ✅ accumulate: 累积
list(accumulate([1, 2, 3, 4]))  # [1, 3, 6, 10]

# ✅ islice: 切片迭代器
list(islice(range(10), 2, 8, 2))  # [2, 4, 6]

# ✅ cycle: 无限循环
from itertools import cycle
counter = cycle([1, 2, 3])
# 无限生成: 1, 2, 3, 1, 2, 3, ...

7. *args 和 **kwargs

# ✅ *args: 可变位置参数
def sum_all(*args):
    return sum(args)

print(sum_all(1, 2, 3, 4))  # 10

# ✅ **kwargs: 可变关键字参数
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=20, city="Beijing")

# ✅ 组合使用
def func(a, b, *args, key1=None, **kwargs):
    print(f"a={a}, b={b}")
    print(f"args={args}")
    print(f"key1={key1}")
    print(f"kwargs={kwargs}")

func(1, 2, 3, 4, key1="value1", key2="value2")
# a=1, b=2
# args=(3, 4)
# key1=value1
# kwargs={'key2': 'value2'}

# ✅ 解包字典作为函数参数
params = {"name": "Alice", "age": 20}
print_info(**params)

8. 上下文管理器 (contextlib)

from contextlib import contextmanager

# ✅ 自定义上下文管理器
@contextmanager
def timer(name):
    import time
    start = time.time()
    print(f"{name} started")
    yield
    end = time.time()
    print(f"{name} finished in {end-start:.2f}s")

# 使用
with timer("Process"):
    # 你的代码
    time.sleep(1)

# ✅ suppress: 忽略特定异常
from contextlib import suppress

with suppress(FileNotFoundError):
    os.remove("non_existent_file.txt")  # 不会抛出异常

9. ChainMap: 链式字典

from collections import ChainMap

# ✅ ChainMap: 合并多个字典视图
defaults = {"color": "red", "user": "guest"}
custom = {"user": "admin"}

# 优先使用 custom 中的值
settings = ChainMap(custom, defaults)
print(settings["user"])   # admin
print(settings["color"])  # red

# 修改只影响第一个字典
settings["theme"] = "dark"
print(custom)  # {'user': 'admin', 'theme': 'dark'}
print(defaults)  # {'color': 'red', 'user': 'guest'}

10. bisect: 二分查找模块

import bisect

# ✅ bisect_left: 找到插入位置
nums = [1, 3, 5, 7, 9]
pos = bisect.bisect_left(nums, 6)
print(pos)  # 3

# ✅ insort: 保持有序插入
bisect.insort(nums, 6)
print(nums)  # [1, 3, 5, 6, 7, 9]

# ✅ 实际应用: 根据分数判定等级
def get_grade(score):
    breakpoints = [60, 70, 80, 90]
    grades = ['F', 'D', 'C', 'B', 'A']
    index = bisect.bisect(breakpoints, score)
    return grades[index]

print(get_grade(85))  # B

11. 链式函数调用

# ✅ 字符串处理链
result = s.strip().lower().replace(' ', '_')

# ✅ Pandas 风格的链式调用
class QueryBuilder:
    def __init__(self, data):
        self.data = data

    def filter(self, condition):
        self.data = [x for x in self.data if condition(x)]
        return self  # 返回self支持链式调用

    def map(self, func):
        self.data = [func(x) for x in self.data]
        return self

    def collect(self):
        return self.data

# 使用
result = (QueryBuilder([1, 2, 3, 4, 5])
    .filter(lambda x: x > 2)
    .map(lambda x: x * 2)
    .collect())  # [6, 8, 10]

📋 Pythonic 代码检查清单

🔍 基础检查 (必须掌握)

在写代码时,问自己这些问题:

✅ 是否使用了列表推导式而不是 for 循环? ✅ 是否使用了 enumerate() 而不是 range(len())? ✅ 是否使用了 zip() 来并行遍历? ✅ 是否使用了 in 来检查成员关系? ✅ 是否使用了三元表达式简化 if-else? ✅ 是否使用了字典的 get() 方法避免 KeyError? ✅ 是否使用了 with 语句管理资源? ✅ 是否使用了 any()all() 简化判断? ✅ 是否充分利用了切片操作 (如 [::-1] 反转)? ✅ 是否使用了序列解包 (如 a, b = b, a)?

🚀 进阶检查 (推荐使用)

✅ 是否使用了 f-string 进行字符串格式化? ✅ 是否使用了 reversed() 进行倒序遍历? ✅ 是否对 None 使用 is 而不是 ==? ✅ 是否使用了 extend()+= 而不是循环 append()? ✅ 是否使用了 sorted()key 参数? ✅ 是否使用了 min()/max()key 参数? ✅ 是否使用了集合运算 (|, &, -, ^)? ✅ 是否使用了 Counter 进行频率统计? ✅ 是否使用了 defaultdict 避免检查键是否存在? ✅ 是否使用了 join() 而不是循环拼接字符串?

💎 高级检查 (算法优化)

✅ 是否可以使用生成器节省内存? ✅ 是否可以使用海象运算符 := (Python 3.8+)? ✅ 是否可以使用 @lru_cache 缓存函数结果? ✅ 是否使用了 operator 模块替代 lambda? ✅ 是否使用了 itertools 的强大工具? ✅ 是否使用了 heapq.nlargest/nsmallest? ✅ 是否使用了 bisect 进行二分操作? ✅ 是否使用了 *args**kwargs? ✅ 是否可以使用上下文管理器简化代码? ✅ 是否可以使用 chain/groupby 处理可迭代对象?


⚠️ 常见反模式 (避免这样写)

1. 不必要的列表遍历

# ❌ 反模式
result = []
for i in range(len(nums)):
    result.append(nums[i] * 2)

# ✅ Pythonic
result = [num * 2 for num in nums]

2. 手动初始化字典键

# ❌ 反模式
word_count = {}
for word in words:
    if word not in word_count:
        word_count[word] = 0
    word_count[word] += 1

# ✅ Pythonic (使用 Counter)
from collections import Counter
word_count = Counter(words)

# ✅ Pythonic (使用 defaultdict)
from collections import defaultdict
word_count = defaultdict(int)
for word in words:
    word_count[word] += 1

3. 循环中的字符串拼接

# ❌ 反模式 (效率低,每次都创建新字符串)
result = ""
for word in words:
    result += word + " "

# ✅ Pythonic
result = " ".join(words)

4. 不使用生成器处理大数据

# ❌ 反模式 (一次性加载到内存)
def read_file(filename):
    with open(filename) as f:
        return [line.strip() for line in f]

# ✅ Pythonic (使用生成器)
def read_file(filename):
    with open(filename) as f:
        for line in f:
            yield line.strip()

5. 忽略内置函数

# ❌ 反模式
max_val = nums[0]
for num in nums[1:]:
    if num > max_val:
        max_val = num

# ✅ Pythonic
max_val = max(nums)

6. 重复计算

# ❌ 反模式 (重复计算斐波那契)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

# ✅ Pythonic (使用缓存)
from functools import lru_cache

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

7. 不必要的类型转换

# ❌ 反模式
if len(my_list) > 0:
    do_something()

# ✅ Pythonic (利用真值测试)
if my_list:
    do_something()

8. 手动实现已有功能

# ❌ 反模式 (手动实现排序查找)
def find_kth_largest(nums, k):
    for i in range(len(nums)):
        for j in range(i+1, len(nums)):
            if nums[i] < nums[j]:
                nums[i], nums[j] = nums[j], nums[i]
    return nums[k-1]

# ✅ Pythonic (使用 heapq)
import heapq
def find_kth_largest(nums, k):
    return heapq.nlargest(k, nums)[-1]

9. 忽略解包特性

# ❌ 反模式
point = (10, 20)
x = point[0]
y = point[1]

# ✅ Pythonic
x, y = point

10. 不使用上下文管理器

# ❌ 反模式
lock.acquire()
try:
    # 操作
    pass
finally:
    lock.release()

# ✅ Pythonic
with lock:
    # 操作
    pass

🎯 性能对比

字符串拼接性能

import timeit

# 循环拼接 (慢)
def concat_loop():
    result = ""
    for i in range(1000):
        result += str(i)
    return result

# join (快 10-100 倍)
def concat_join():
    return "".join(str(i) for i in range(1000))

print(timeit.timeit(concat_loop, number=1000))  # ~0.15s
print(timeit.timeit(concat_join, number=1000))  # ~0.015s

列表推导式 vs 循环

# 循环 append
def loop_append():
    result = []
    for i in range(10000):
        result.append(i * 2)
    return result

# 列表推导式 (快 30% 左右)
def list_comp():
    return [i * 2 for i in range(10000)]

print(timeit.timeit(loop_append, number=1000))  # ~0.6s
print(timeit.timeit(list_comp, number=1000))    # ~0.4s

set 查找 vs list 查找

big_list = list(range(10000))
big_set = set(range(10000))

# list 查找: O(n)
timeit.timeit(lambda: 9999 in big_list, number=10000)  # ~0.5s

# set 查找: O(1) (快 1000+ 倍)
timeit.timeit(lambda: 9999 in big_set, number=10000)   # ~0.0005s

🎓 小结

Pythonic 代码的五大原则

简洁性: 用更少的代码表达更多的意思

  • 列表推导式 > 循环 append
  • enumerate/zip > range(len())
  • 内置函数 > 手动实现

可读性: 代码要清晰易懂,不要过度聪明

  • f-string > 字符串拼接
  • if x in [1,2,3] > if x==1 or x==2 or x==3
  • 有意义的变量名 > 单字母变量

惯用法: 遵循 Python 社区的最佳实践

  • with 管理资源
  • is None 不用 == None
  • 序列解包 a, b = b, a

效率: 选择合适的数据结构和算法

  • set 查找 > list 查找
  • join() 拼接 > 循环 +=
  • defaultdict > 手动初始化

显式优于隐式: 代码应该明确表达意图

  • 类型提示 (type hints)
  • 清晰的函数/变量命名
  • 适当的注释说明

学习路径建议

  1. 基础阶段: 掌握前 20 个常规用法
  2. 进阶阶段: 学习 collections、itertools 等标准库
  3. 高级阶段: 掌握生成器、装饰器、上下文管理器
  4. 实践阶段: 在 LeetCode 题目中应用这些技巧

Pythonic 编程格言

"There should be one-- and preferably only one --obvious way to do it."

"Simple is better than complex."

"Readability counts."

-- The Zen of Python

核心原则: 写出让其他 Python 程序员一眼就能看懂的代码!


🔗 相关章节

延伸学习: PEP 8 (Python代码风格指南)


如果这篇内容对你有帮助,推荐收藏 AI Compass:github.com/tingaicompa… 更多系统化题解、编程基础和 AI 学习资料都在这里,后续复习和拓展会更省时间。