1. 迭代对象解压赋值
解压赋值操作可以应用到任何迭代对象上,如:列表、元组、字符串、文件对象、迭代器、生成器。
唯一的要求:
变量的数量必须跟序列元素的数量是一样的。
>>> p=(1,2,3,4)
>>> a,b,c,d=p
>>> a
1
>>> b
2
>>> c
3
>>> d
4
>>> datas=['apple', 'cherry', 1, (1,2,3,4)]
>>> a,b,c,d=datas
>>> a
'apple'
>>> b
'cherry'
>>> c
1
>>> d
(1, 2, 3, 4)
>>> s='faris'
>>> a,b,c,d,e=s
>>> a
'f'
>>> b
'a'
>>> c
'r'
>>> d
'i'
>>> e
's'
2. 扩展迭代对象解压赋值
如果遇到不确定个数或任意个数元素的可迭代对象时,则需要使用星号表达式可以用来解决这个问题。
假设你现在有一些用户的记录列表,每条记录包含一个名字、邮件,接着就是不确定数量的电话号码。
>>> record = ('Dave', 'dave@example.com', '773-555-1212', '847-555-1212')
>>> name, email, *phone_numbers = record
>>> name
'Dave'
'dave@example.com'
>>> phone_numbers
['773-555-1212', '847-555-1212']
>>>
如果你想解压一些元素后丢弃它们,你不能简单就使用 * , 但是你可以使用一个普通的废弃名称,比如 _ 或者 ign (ignore)。
>>> record = ('ACME', 50, 123.45, (12, 18, 2012))
>>> name, *_, (*_, year) = record
>>>
>>>
>>>
>>> name
'ACME'
>>> _
[12, 18]
>>>
>>>
>>> year
2012
3. 查找最大或最小的 N 个元素
heapq 模块有两个函数:nlargest() 和 nsmallest() 可以完美解决这个问题。
输出最大和最小的三个值:
>>> import heapq
>>> nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
>>> print(heapq.nlargest(3, nums))
[42, 37, 23]
>>> print(heapq.nsmallest(3, nums))
[-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'])
>>>
>>> cheap
[{'name': 'YHOO', 'shares': 45, 'price': 16.35}, {'name': 'FB', 'shares': 200, 'price': 21.09}, {'name': 'HPQ', 'shares': 35, 'price': 31.75}]
>>>
>>> expensive
[{'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'ACME', 'shares': 75, 'price': 115.65}, {'name': 'IBM', 'shares': 100, 'price': 91.1}]
注意点
当要查找的元素个数相对比较小的时候,函数 nlargest() 和 nsmallest() 是很合适的。
如果你仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用 min() 和 max() 函数会更快些。
如果 N 的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点 ( sorted(items)[:N] 或者是 sorted(items)[-N:] )。
4. 实现一个优先级队列
import heapq
class PriorityQueue:
def __init__(self):
self._queue = []
self._index = 0
def push(self, item, priority):
heapq.heappush(self._queue, (-priority, self._index, item))
self._index += 1
def pop(self):
return heapq.heappop(self._queue)[-1]
class Item:
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Item({!r})'.format(self.name)
q = PriorityQueue()
q.push(Item('foo'), 1)
q.push(Item('bar'), 5)
q.push(Item('spam'), 4)
q.push(Item('grok'), 1)
q.pop()
q.pop()
q.pop()
q.pop()
在上面代码中,队列包含了一个 (-priority, index, item) 的元组。 优先级为负数的目的是使得元素按照优先级从高到低排序。 这个跟普通的按优先级从低到高排序的堆排序恰巧相反。
对于Item对象是不支持相互比较的:
>>> a=Item('foo')
>>> b=Item('boo')
>>> a > b
Traceback (most recent call last):
File "test.py", line 26, in
a > b
TypeError: '>' not supported between instances of 'Item' and 'Item'
但是使用元组,则可以进行比较:
>>> class Item:
... def __init__(self, name):
... self.name = name
... def __repr__(self):
... return 'Item({!r})'.format(self.name)
...
>>>
>>> a=(1, Item('foo'))
>>> b=(2, Item('boo'))
>>> print (a > b)
False
5. 字典中的键映射多个值 multidict
一个字典就是一个键对应一个单值的映射。如果你想要一个键映射多个值,那么你就需要将这多个值放到另外的容器中, 比如列表或者集合里面。
d = {
'a' : [1, 2, 3],
'b' : [4, 5]
}
e = {
'a' : {1, 2, 3},
'b' : {4, 5}
}
使用 collections 模块中的 defaultdict 来构造一键多值的字典:
>>> 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
defaultdict(, {'a': {1, 2}, 'b': {4}})
defaultdict 会自动为将要访问的键(就算目前字典中并不存在这样的键)创建映射实体。
>>> d = defaultdict(set)
>>>
>>>
>>> d['d']
set()
>>> d
defaultdict(, {'d': set()})
可以通过一个普通的字典上使用 setdefault() 去除这个情况:
>>> d = {}
>>> d.setdefault('a', []).append(1)
>>> d.setdefault('a', []).append(2)
>>> d.setdefault('b', []).append(4)
>>>
>>> d
{'a': [1, 2], 'b': [4]}
>>> d['c']
Traceback (most recent call last):
File "", line 1, in
KeyError: 'c'
>>>
>>> d['a']
[1, 2]
这种写法是让人非常别扭的,因为需要多些一次[]。
也可以自己实现:
d = {}
for key, value in pairs:
if key not in d:
d[key] = []
d[key].append(value)
但是从Python提倡的简洁上来说,没有defaultdict简洁:
d = defaultdict(list)
for key, value in pairs:
d[key].append(value)
6. 字典按顺序输出
为了能控制一个字典中元素的顺序,你可以使用 collections 模块中的 OrderedDict 类
>>> from collections import OrderedDict
>>>
>>> d = OrderedDict()
>>> d['foo'] = 1
>>> d['bar'] = 2
>>> d['spam'] = 3
>>> d['grok'] = 4
>>>
>>> d
OrderedDict([('foo', 1), ('bar', 2), ('spam', 3), ('grok', 4)])
>>>
>>> for key in d:
... print(key, d[key])
...
foo 1
bar 2
spam 3
grok 4
OrderedDict 内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元素插入进来的时候, 它会被放到链表的尾部。
一个 OrderedDict 的大小是一个普通字典的两倍,因为它内部维护着另外一个链表。 大量数据时,需要权衡效率。
7. 字典运算
如何在数据字典中 执行 求最小值、最大值、排序?
上面我们学习的方法为:
使用heapq 中的 nlargest、nsmallest、heapify完成堆排序。
使用 sorted函数。
使用 min函数 和 max函数
参考股票名和价格映射字典:
prices = {
'ACME': 45.23,
'AAPL': 612.78,
'IBM': 205.55,
'HPQ': 37.20,
'FB': 10.75
}
7.1 heapq
显然无法实现字典排序,无论是根据key排序,还是根据value排序。
>>> heapq.nlargest(1, prices)
['IBM']
>>> heapq.nsmallest(1, prices)
['AAPL']
>>> heapq.heapify(prices)
Traceback (most recent call last):
File "", line 1, in
TypeError: heap argument must be a list
7.2 sorted
显然 sorted无法实现对value的排序,只能对key进行排序并返回排好序的key列表,且还需要再次遍历这个列表才能获取value。
>>> sorted(prices)
['AAPL', 'ACME', 'FB', 'HPQ', 'IBM']
7.2 min max
显然和sorted是相同的问题,只能对key进行排序。
>>> min(prices)
'AAPL'
>>>
>>>
>>> max(prices)
'IBM'
方案1 zip:
我们为了对值进行操作时,需要使用zip() 函数对key与value进行翻转。
>>> list(zip(prices.values(), prices.keys()))<