目录
- 1: 避免多层分支嵌套,能提前结束就提前结束:
- 2: 封装那些过于复杂的逻辑判断
- 3 : 使用“德摩根定律”
- 4: 自定义对象的“布尔真假”
- 5: 在条件判断中使用 all() / any()
- 1: enumerate() 的使用:
- 2: 使用 product 扁平化多层嵌套循环
- 3: 使用 islice 实现循环内隔行处理
- 4: 使用 takewhile 替代 break 语句
- 5: 使用生成器编写自己的修饰函数
- 6: 按职责拆解循环体内复杂代码块
一: 选择分支结构
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