带你读本炒菜书-【原创】

哈喽,大家好,我是知道。

今天给大家来详细聊聊最近读的一本耳熟能详的python秘籍cookbook。
这本书现在已经出了第三版,依旧值得大家一读。

第一章:数据结构和算法

1. 解压可迭代对象赋值给多个变量

>>> *trailing, current = [10, 8, 7, 1, 9, 5, 10, 3]
>>> trailing
[10, 8, 7, 1, 9, 5, 10]
>>> current
3

2. 最后有限几个元素的历史记录

from collections import deque
def search(lines, pattern, history=5):
    previous_lines = deque(maxlen=history)
    for line in lines:
        if pattern in line:
            yield line, previous_lines
        previous_lines.append(line)
# Example use on a file
if __name__ == '__main__':
    with open(r'../../cookbook/somefile.txt') as f:
        for line, prevlines in search(f, 'python', 5):
            for pline in prevlines:
                print(pline, end='')
            print(line, end='')
            print('-' * 20)

我们在写查询元素的代码时,通常会使用包含 yield 表达式的生成器函数,这样可以将搜索过程代码使用搜索结果代码解耦。
使用 deque(maxlen=N) 构造函数会新建一个固定大小的队列。当新的元素加入并且这个队列已满的时候,最老的元素会自动被移除掉。
在队列两端插入或删除元素时间复杂度都是 O(1) ,而在列表的开头插入或删除元素的时间复杂度为 O(N) 。

3. 从一个集合中获得最大或者最小的 N 个元素列表(使用堆)

import heapq
nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
print(heapq.nlargest(3, nums)) # Prints [42, 37, 23]
print(heapq.nsmallest(3, nums)) # Prints [-4, 1, 2]

# 也可接受关键字参数,用于更复杂数据结构中
portfolio = [ {'name': 'IBM', 'shares': 100, 'price': 91.1},
{'name': 'AAPL', 'shares': 50, 'price': 543.22},
{'name': 'FB', 'shares': 200, 'price': 21.09},
{'name': 'HPQ', 'shares': 35, 'price': 31.75},
{'name': 'YHOO', 'shares': 45, 'price': 16.35},
{'name': 'ACME', 'shares': 75, 'price': 115.65} ]
cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
  • N较小时,函数 nlargest() 和 nsmallest()
  • N=1的元素的话,那么使用 min() 和max() 函数会更快些
  • N 的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快(sorted(items)[:N] 或者是 sorted(items)[-N:])

4. 实现一个优先级队列,priority越大优先级越高(使用堆)

import heapq
class PriorityQueue:
    def __init__(self):
        self._queue = []
        self._index = 0
    def push(self, item, priority):
        # 构建堆时,默认是创建小堆,及最上面的元素始终是最小的,所以-priority表示最大, index表示优先级相同时,谁先进就谁最大
        heapq.heappush(self._queue, (-priority, self._index, item))
        self._index += 1
    def pop(self):
        print(self._queue)
        return heapq.heappop(self._queue)[-1]

函数 heapq.heappush() 和 heapq.heappop() 分别在队列 _queue 上插入和删除第一个元素,并且队列 _queue 保证第一个元素拥有最高优先级。heappop() 函数总是返回”最小的”的元素,这就是保证队列 pop 操作返回正确元素的关键。另外,由于 push 和 pop操作时间复杂度O(log N),其中 N 是堆的大小,因此就算是 N 很大的时候它们运行速度也依旧很快。

5. 字典中的键映射多个值

  • 你可以很方便的使用 collections 模块中的 defaultdict 来构造这样的字典。defaultdict 的一个特征是它会自动初始化每个 key 刚开始对应值

    from collections import defaultdict
    d = defaultdict(list)
    d['a'].append(1)
    d['a'].append(2)
    d['b'].append(4) d = defaultdict(set)
    d['a'].add(1)
    d['a'].add(2)
    d['b'].add(4)
  • 方法二

    d = {} # A regular dictionary
    d.setdefault('a', []).append(1)
    d.setdefault('a', []).append(2)
    d.setdefault('b', []).append(4)
    print(d)  # {'a': [1, 2], 'b': [4]}

    6. 字典排序

    • 可 以 使 用 collections 模 块 中 的OrderedDict 类。在迭代操作的时候它会保持元素被插入时的顺序
      from collections import OrderedDict
      d = OrderedDict()
      d['foo'] = 1
      d['bar'] = 2
      d['spam'] = 3
      d['grok'] = 4
      # Outputs "foo 1", "bar 2", "spam 3", "grok 4"
      for key in d:
      print(key, d[key])

      需要注意的是,一个 OrderedDict 的大小是一个普通字典的两倍,因为它内部维护着另外一个链表。所以如果你要构建一个需要大量 OrderedDict 实例的数据结构的时候(比如读取 100,000 行 CSV 数据到一个 OrderedDict 列表中去),那么你就得仔细权衡一下是否使用 OrderedDict 带来的好处要大过额外内存消耗的影响。

7. 在数据字典中执行一些计算操作(比如求最小值、最大值、排序等等)

prices = {
    'ACME': 45.23,
    'AAPL': 612.78,
    'IBM': 205.55,
    'HPQ': 37.20,
    'FB': 10.75
    }
min_price = min(zip(prices.values(), prices.keys()))
# min_price is (10.75, 'FB')
max_price = max(zip(prices.values(), prices.keys()))
# max_price is (612.78, 'AAPL')
prices_sorted = sorted(zip(prices.values(), prices.keys()))
# prices_sorted is [(10.75, 'FB'), (37.2, 'HPQ'),
# (45.23, 'ACME'), (205.55, 'IBM'),
# (612.78, 'AAPL')]

执行这些计算的时候,需要注意的是 zip() 函数创建的是一个只能访问一次的迭代器。

  • 你在一个字典上执行普通的数学运算,你会发现它们仅仅作用于键,而不是值。比如:
    min(prices) # Returns 'AAPL'
    max(prices) # Returns 'IBM'
  • 你可能还想要知道对应的键的信息(比如哪种股票价格是最低)
    min(prices, key=lambda k: prices[k]) # Returns 'FB'
  • 很不幸,你如果想知道值还需要再取一次值
    min_value = prices[min(prices, key=lambda k: prices[k])]
  • 需要注意的是在计算操作中使用到了 (值,键) 对。当多个实体拥有相同的值的时候,键会决定返回结果。
    >>> prices = { 'AAA' : 45.23, 'ZZZ': 45.23 }
    >>> min(zip(prices.values(), prices.keys()))
    (45.23, 'AAA')
    >>> max(zip(prices.values(), prices.keys()))
    (45.23, 'ZZZ')

    8. 怎样在两个字典中寻寻找相同点(比如相同的键、相同的值等等)

一个字典就是一个键集合与值集合的映射关系。字典的 keys() 方法返回一个展现键集合的键视图对象。它们支持集合操作,比如集合并、交、差运算

a.keys() & b.keys() # { 'x', 'y' }
# Find keys in a that are not in b
a.keys() - b.keys() # { 'z' }
# Find (key,value) pairs in common
a.items() & b.items() # { ('y', 2) }

是不是加深了你对常用方法的理解,后台回复:炒菜 即可下载最新中文版cookbook

最后

更多Python知识尽在【Python都知道】公众号,欢迎大家!!
扫描下方二维码,关注公众号,了解更多Python内容


小白学堂 » 带你读本炒菜书-【原创】

就聊挣钱,一个带着你做副业的社群。

立即查看 了解详情