创建网站花钱吗,地方生活门户信息网站源码,石家庄企业建站,vue网站开发教程第 29 条 用赋值表达式消除推导中的重复代码
推导 list、dict 与 set 等变体结构时#xff0c;经常要在多个地方用到同一个计算结果。例如#xff0c;我们要给制作紧固件等公司编写程序来管理订单。顾客下单后#xff0c;我们要判断当前的库存能否满足这份订单#xff…第 29 条 用赋值表达式消除推导中的重复代码
推导 list、dict 与 set 等变体结构时经常要在多个地方用到同一个计算结果。例如我们要给制作紧固件等公司编写程序来管理订单。顾客下单后我们要判断当前的库存能否满足这份订单也就是说要核查每种产品的数量有没有达到可以发货的最低限制8 个为一批至少要有一批才能发货。
stocks {nails: 125,screw: 35,wingnuts: 8,washers: 24,
}order [screws, wingnuts, clips]def get_batches(count, size):return count // sizeresult {}
for name in order:count stocks.get(name, 0)batches get_batches(count, 8)if batches:result[name] batchesprint(result)
{screws: 4, wingnuts: 1}
这段逻辑如果改用字典来写会简单一些参见第 27 条。
found {name: get_batches(stocks.get(name, 0), 8)for name in orderif get_batches(stocks.get(name, 0), 8)}
print(found)
{screws: 4, wingnuts: 1} 这样写虽然比刚才简短但问题是它把 get_batches(stock.get(name, 0), 8)写成了两遍。这样写会让代码看着比较乱而且实际上程序也没有必要把这个运算结果计算两遍。另外如果这两个地方都忘了同步更新那么程序就会出现 bug。例如我们决定每一批不是 8 个而是 4 个那么需要把 get_batches 的第二个参数从 8 改成 4但是万一我们忘了同步修改另一个地方那么代码就会出现问题它会把大于等于 4 但是小于 8 的情况给漏掉。
has_bug {name: get_batches(stocks.get(name, 0), 4)for name in orderif get_batches(stocks.get(name, 0), 8)}print(Expected:, found)
print(Found:, has_bug)
Expected: {screws: 4, wingnuts: 1}
Found: {screws: 8, wingnuts: 2} 有个简单的办法可以解决这个问题那就是在推导的过程中使用 Python 3.8 新引入的 : 操作符进行赋值表达参见 第10条。
found {name: batches for name in orderif (batches : get_batches(stocks.get(name, 0), 8))} 这条 batches : get_batches(…) 赋值表达式能够从 stocks 字典中查到对应商品一共有几批并且把这个批数放在 batches 变量里。这样的话我们推导这个产品所对应批数时就不用通过 get_batches 计算了因为这样结果已经保存到 batches 里面了。这种方法只需要把 get 与 get_batches 调用一次即可这样能够提高效率因为我们不需要针对 order 列表中的每件产品都多做一次 get 与 get_batches。
在推导过程中描述新值的那一部分也可以出现赋值表达式。但如果在其他部分引用了定义在那一部分的变量那么程序就可能在运行时出错。例如如果写成了下面这样那么程序就需要先考虑 for name, count in stocks.items() if tenth 0,而这个时候其中的 teeth 时没有得到定义。
result {name: (tenth : count // 10)for name, count in stocks.items() if tenth 0}
Traceback ...
NameError: name tenth is not defined 如果推导逻辑不含条件可以把赋值表达式移动到 if 条件里面然后在描述新值的这一部分引用已经定义过的 tenth 变量。
result {name: tenth for name, count in stocks.items() if (tenth : count // 10) 0}
{nails: 12, screws: 3, washers: 2} 如果推导逻辑不带条件而表示新值的那一部分又使用了 : 操作符那么操作符左边的变量就会泄漏到包含这条推导语句的那个作用域里面。参见 第21条。
half [(last : count // 2) for count in stocks.values()]
print(fLast item of {half} is {last})
Last item of [62, 17, 4, 12] is 12 这与普通的 for 循环所用的那个循环变量相似。
for count in stocks.values(): # Leaks loop variablepass
print(fLast item of {list(stocks.values())} is {count}) 然而推导语句中的 for 循环所使用的循环变量是不会像刚才那样泄漏到外面的。
half [count // 2 for count in stocks.values()]
print(half)
print(count)
[62, 17, 4, 12]
Traceback ...
NameError: name count is not defined. Did you mean: round? 最好不要泄漏循环变量所以建议赋值语句只出现在推导逻辑的条件之中。
赋值表达式不仅可以用在推导过程中而且可以用来编写生成器表达式 generator expression参见 第 32 条。下面这种写法创建的是迭代器而不是字典实例该迭代器会给出一对数值其中第一个元素为产品的名字第二个元素为这种产品的库存。
found ((name, batches) for name in orderif (batches : get_batches(stocks.get(name, 0), 8)))
print(next(found))
print(next(found))
(screws, 4)
(wingnuts, 1)