目录




一: 选择分支结构

1: 避免多层分支嵌套,能提前结束就提前结束:


  • 优化前:

def buy_fruit(nerd, store):
"""去水果店买苹果

- 先得看看店是不是在营业
- 如果有苹果的话,就买 1 个
- 如果钱不够,就回家取钱再来
"""
if store.is_open():
if store.has_stocks("apple"):
if nerd.can_afford(store.price("apple", amount=1)):
nerd.buy(store, "apple", amount=1)
return
else:
nerd.go_home_and_get_money()
return buy_fruit(nerd, store)
else:
raise MadAtNoFruit("no apple in store!")
else:
raise MadAtNoFruit("store is closed!")

  • 优化后:
def buy_fruit(nerd, store):
if not store.is_open():
raise MadAtNoFruit("store is closed!")

if not store.has_stocks("apple"):
raise MadAtNoFruit("no apple in store!")

if nerd.can_afford(store.price("apple", amount=1)):
nerd.buy(store, "apple", amount=1)
return
else:
nerd.go_home_and_get_money()
return buy_fruit(nerd, store)
  • 2: 封装那些过于复杂的逻辑判断
  • 如果判断的语句太长,就用函数把条件拆开
# 如果活动还在开放,并且活动剩余名额大于 10,为所有性别为女性,或者级别大于 3
# 的活跃用户发放 10000 个金币
if activity.is_active and activity.remaining > 10 and \
user.is_active and (user.sex == 'female' or user.level > 3):
user.add_coins(10000)
return

3 : 使用“德摩根定律”

  • 德摩根定律就是 ​​not A or not B​​​ 等价于 ​​not (A and B)​​。通过这样的转换

4: 自定义对象的“布尔真假”

  • 通过定义魔法方法 ​​__len__​​​ 和 ​​__bool__​​ ,我们可以让类自己控制想要表现出的布尔真假值,让代码变得更 pythonic。

5: 在条件判断中使用 all() / any()


  • ​all(seq)​​​:仅当 ​​seq​​​ 中所有对象都为布尔真时返回 ​​True​​​,否则返回 ​​False​
  • ​any(seq)​​​:只要 ​​seq​​​ 中任何一个对象为布尔真就返回 ​​True​​​,否则返回 ​​False​

二: 地道的循环结构

1: enumerate() 的使用:

  • ​enumerate()​​​ 是 Python 的一个内置函数,它接收一个“可迭代”对象作为参数,然后返回一个不断生成 ​​(当前下标, 当前元素)​​ 的新可迭代对象

2: 使用 product 扁平化多层嵌套循环


  • ​product()​​ 可以接收多个可迭代对象,然后根据它们的笛卡尔积不断生成结果。
  • 优化前的代码:

def find_twelve(num_list1, num_list2, num_list3):
"""从 3 个数字列表中,寻找是否存在和为 12 的 3 个数
"""
for num1 in num_list1:
for num2 in num_list2:
for num3 in num_list3:
if num1 + num2 + num3 == 12:
return num1, num2, num3

  • 优化后的代码:
from itertools import product
def find_twelve_v2(num_list1, num_list2, num_list3):
for num1, num2, num3 in product(num_list1, num_list2, num_list3):
if num1 + num2 + num3 == 12:
return num1, num2, num3

3: 使用 islice 实现循环内隔行处理


  • ​islice(seq, start, end, step)​​ 函数和数组切片操作*( list[start:stop:step] )​有着几乎一模一样的参数。如果需要在循环内部进行隔行处理的话,只要设置第三个递进步长参数 step 值为 2 即可​(默认为 1)*。
  • 优化前代码:

def parse_titles(filename):
"""从隔行数据文件中读取 reddit 主题名称
"""
with open(filename, 'r') as fp:
for i, line in enumerate(fp):
# 跳过无意义的 '---' 分隔符
if i % 2 == 0:
yield line.strip()

  • 优化之后:
from itertools import islice

def parse_titles_v2(filename):
with open(filename, 'r') as fp:
# 设置 step=2,跳过无意义的 '---' 分隔符
for line in islice(fp, 0, None, 2):
yield line.strip()

4: 使用 takewhile 替代 break 语句


  • ​takewhile(predicate, iterable)​​ 会在迭代 ​​iterable​​ 的过程中不断使用当前对象作为参数调用 ​​predicate​​ 函数并测试返回结果,如果函数返回值为真,则生成当前对象,循环继续。否则立即中断当前循环。
  • 优化前:

for user in users:
# 当第一个不合格的用户出现后,不再进行后面的处理
if not is_qualified(user):
break

  • 优化后:
from itertools import takewhile

for user in takewhile(is_qualified, users):

5: 使用生成器编写自己的修饰函数

def even_only(numbers):
for num in numbers:
if num % 2 == 0:
yield num


def sum_even_only_v2(numbers):
"""对 numbers 里面所有的偶数求和"""
result = 0
for num in even_only(numbers):
result += num
return result

6: 按职责拆解循环体内复杂代码块