使用内置数据结构和算法
当你实现非常小的的Python程序时,你可能会看到由你的代码的算法复杂性而造成的减速。 这个通常不是Python语言本身速度的造成,这更有可能是因为没有为您的问题使用最好的算法和数据结构。幸运的是Python标准库有许多内置的算法和数据结构可以使用。除了速度,使用这些常用的算法和数据结构可以让你的生活更轻松。 你可能想使用的一些更有力的工具,这是一个棘手的问题。 避免重新实现常用功能将会节省您的时间。
Double-ended Queue(双端队列)
deque类是在collections模块中,它是一个double-ended队列。从deque队列开始或者结尾,插入或者删除会花费相同的时间。这个使其成为先进先出(FIFO)队列的理想选择。
fifo = deque()
fifo.append(1) # Producer
x = fifo.popleft() # Consumer
内置List也可以实现有序队列,如fifo。但内置List从列表头部的插入或删除项,花费时间是线性的,这比常数慢得多。
Ordered Dictionary(有序字典)
标准字典是无序的。 这意味着具有相同的键和值的dict可以有不同的迭代次序。 这种行为有一个令人惊讶的副产品就是实现字典的快速哈希表。
a = {}
a['foo'] = 1
a['bar'] = 2
# Randomly populate ‘b’ to cause hash conflicts
while True:
z = randint(99, 1013)
b = {}
for i in range(z):
b[i] = i
b['foo'] = 1
b['bar'] = 2
for i in range(z):
del b[i]
if str(b) != str(a):
break
print(a)
print(b)
print('Equal?', a == b)
>>>
{'foo': 1, 'bar': 2}
{'bar': 2, 'foo': 1}
Equal? True
collections模块中的OrderedDict类是一种特殊类型的字典,它跟踪其键的插入顺序。 迭代键OrderedDict具有可预测的行为。 这可以大大简化测试和调试通过使所有代码确定性。
a = OrderedDict()
a['foo'] = 1
a['bar'] = 2
b = OrderedDict()
b['foo'] = 'red'
b['bar'] = 'blue'
for value1, value2 in zip(a.values(), b.values()):
print(value1, value2)
>>>
1 red
2 blue
Default Dictionary
字典对记账和跟踪统计非常有用。内建的字典类型是不能假设任何键已经存在。 这使得它做一些简单的事情时显得笨拙,如增加一个存储在字典中的计数器。
stats = {}
key = 'my_counter'
if key not in stats:
stats[key] = 0
stats[key] += 1
collections模块中的defaultdict类简化了当key不存在时自动存储默认值。 所有你需要做的是提供每次键丢失时将返回默认值的函数。 在这里例如,int内置函数返回0现在,递增计数器是
简单。int()->0
stats = defaultdict(int)
stats['my_counter'] += 1
Heap Queue
关于这里,heap这种数据结构的介绍有一个简单的blog可以去看一下http://blog.youkuaiyun.com/minxihou/article/details/51857518
堆是用于维护优先级队列的有用数据结构。 heapq模块提供了在标准list类型中创建堆的功能使用函数heappush,heappop和nsmallest等函数。任何优先级的项可以按任何顺序插入堆中。
a = []
heappush(a, 5)
heappush(a, 3)
heappush(a, 7)
heappush(a, 4)
总是先移除最高优先级(lowest number)的项.
print(heappop(a), heappop(a), heappop(a), heappop(a))
>>>
3 4 5 7
生成的list在heapq之外很容易使用。 访问堆的0索引将总是返回最小的项。
a = []
heappush(a, 5)
heappush(a, 3)
heappush(a, 7)
heappush(a, 4)
assert a[0] == nsmallest(1, a)[0] == 3
list的sort方法保持不变。
print('Before:', a)
a.sort()
print('After:' , a)
>>>
Before: [3, 4, 7, 5]
After: [3, 4, 5, 7]
Bisection
调用index方法查找列表中的项需要花费与list长度成线性比例的时间。
x = list(range(10**6))
i = x.index(991234)
使用bisect模块的方法,如:bisect_left,是使用二分查找的方法。它返回的索引是插入点值插入序列。
i = bisect_left(x, 991234)
二分搜索的复杂度是对数的。 这意味着使用bisect搜索100万个项的list的速度是使用线性索引方式搜索的14倍。It’s way faster!
Iterator Tools
tertools内置模块包含大量有用与迭代器相关的函数。不是所有这些都在Python 2中可用,但它们可以轻松地使用通过查看模块中记录的simple recipes。 请参阅help(itertools)获得更多详细信息。
itertools中的函数主要分为三类:
Linking iterators together
•chain:将多个迭代器组合成一个顺序迭代器。
•cycle:一直重复迭代器的项。
•tee:将单个迭代器拆分为多个并行迭代器。
•zip_longest:内置zip函数的变体,当迭代的几个对象长度不同的时候有更好的表现。
Filtering items from an iterator
•islice:通过数字索引切片迭代器,而不进行复制。
•takewhile:当断言函数返回Ture时返回迭代器中的项。
•dropwhile:当断言函数第一次为False时,返回迭代器中的项。
•filterfalse:当断言函数第一次为False时,返回迭代器中所有的项。 与内置函数filter作用相反。
Combinations of items from iterators(组合迭代器中的项)
•product:返回迭代器中项的笛卡尔乘积,是一种很好的替代深层嵌套列表推导的方法。
•permutations:返回长度为N的有序排列迭代器。
•combination:返回长度为N的,用迭代器中未重复项所组成的无序组合。
在itertools模块中有更多的功能和recipes可用不能在这里一一提及。 每当你发现自己处理一些棘手的迭代代码,itertools文档是值得再次查看,看看是否有你想要的东西。
Things to Remember
1、使用Python的内置模块用于算法和数据结构。
2、不要自己重新实现此功能。