预计阅读本页时间:-
第 10 章 性能与优化
“过早地优化是万恶之源。”
——Donald Knuth,摘自Structured Programming with go to Statements
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
10.1 数据结构
如果使用正确的数据结构,大多数计算机问题都能以一种优雅而简单的方式解决,而Python就恰恰提供了很多可供选择的数据结构。
通常,有一种诱惑是实现自定义的数据结构,但这必然是徒劳无功、注定失败的想法。因为Python总是能够提供更好的数据结构和代码,要学会使用它们。
例如,每个人都会用字典,但你看到过多少次这样的代码:
def get_fruits(basket, fruit):
# A variation is to use "if fruit in basket:"
try:
return basket[fruit]
except KeyError:
return set()
最好是使用dict结构已经提供的get方法。
def get_fruits(basket, fruit):
return basket.get(fruit, set())
使用基本的Python数据结构但不熟悉它提供的所有方法并不罕见。这也同样适用于集合的使用。例如:
def has_invalid_fields(fields):
for field in fields:
if field not in ['foo', 'bar']:
return True
return False
这可以不用循环实现:
def has_invalid_fields(fields):
return bool(set(fields) - set(['foo', 'bar']))
set数据结构包含许多能解决不同问题的方法,否则这些问题需要通过嵌套的for/if块才能实现。
还有许多高级的数据结构可以极大地减少代码维护负担。例如,可以看看下面的代码:
def add_animal_in_family(species, animal, family):
if family not in species:
species[family] = set()
species[family].add(animal)
species = {}
add_animal_in_family(species, 'cat', 'felidea')
当然,这段代码是完全有效的,但想想看你会在你的程序中需要多少次上面代码的变种?10次?100次?
Python提供的collections.defaultdict结构可以更优雅地解决这个问题。
import collections
def add_animal_in_family(species, animal, family):
species[family].add(animal)
species = collections.defaultdict(set)
add_animal_in_family(species, 'cat', 'felidea')
每次试图从字典中访问一个不存在的元素,defaultdict都会使用作为参数传入的这个函数去构造一个新值而不是抛出KeyError。在这个例子,set函数被用来在每次需要时构造一个新的集合。
此外,collections模块提供了一些新的数据结构用来解决一些特定问题,如OrderedDict或者Counter。
在Python中找到正确的数据结构是非常重要的,因为正确的选择会节省你的时间并减少代码维护量。