1.星号表达式
星号解压 : 实际上 *args 可以表示很多值.
In [1]: for tag, *args in [('foo',1,2),('bar','hello')]:
...: print(tag)
...: print(*args)
...: print('\n')
...:
foo
1 2
bar
hello
接下来,请注意与以上的区别
In [2]: for tag, *args in [('foo',1,2),('bar','hello')]:
...: print(tag)
...: print(args)
...: print('\n')
...:
foo
[1, 2]
bar
['hello']
当你给值赋予变量,且值的个数不确定的时候.可以使用星号表达式 , *args 可以生成任意个变量 . 但是此时args是一个列表.如果想要将列表中的元素分别传递,那么你需要 *args 进行 ' 解压 '.对,没错,就是解压.
请看下面的练习
>>> items = [1, 10, 7, 4, 5, 9]
>>> head, *tail = items
>>> head
1
>>> tail
[10, 7, 4, 5, 9]
>>>
2.deque(maxlen=N)构造函数
这个函数会新建一个固定大小的队列.当新的元素加入并且这个队列已经满的时候,最老的元素会自动被移除掉.
In [3]: from collections import deque
In [4]: q = deque()
In [5]: q.append(2)
In [6]: q.append(3444)
In [7]: q.append(99)
In [8]: q
Out[8]: deque([2, 3444, 99])
In [9]: q.append(0)
In [10]: q
Out[10]: deque([2, 3444, 99, 0])
在队列两端插入或者删除元素时间复杂度都是O(1) , 而在列表的开头插入或者删除元素的时间复杂度为O(n)
3.匿名函数
关键字 lambda 表示匿名函数,冒号前的 x 表示函数参数
匿名函数有个限制 , 就是只能有一个表达式 , 不用写 return ,返回值就是该表达式的结果
匿名函数本身也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
>>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)
25
4.如何从一个集合中获得最小或者最大的N个元素 ?
(1)当要查找的元素个数相对比较小的时候,heapq 模块 的nlargest() 和 nsmallest() 是很合适的.
(2) 如果你仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用 min() 和 max() 函数会更快些
(3) 如果 N 的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点(sorted(items)[:N] 或者是 sorted(items)[-N:])
5.类
类(class):
一种程序员自定义的类型。类定义创建了一个新的类对象。
类对象(class object):
包含程序员自定义类型的细节信息的对象。类对象可以被用于创建该类型的实例
定义一个矩形类,指定矩形的一个角(或者中心) 宽度 以及 长度 .
class Point:
"""Represents a point in 2-D space."""
class Rectangle:
"""Represents a rectangle.
attributes: width, height, corner.
"""
文档中列出了属性: width height;corner 是一个 point 对象,代表左下角的那个点.
进行赋值
box = Rectangle()
box.width = 100.0
box.height = 200.0
box.corner = Point()
box.corner.x = 0.0
box.corner.y = 0.0
Rectangle 是一个 类 .
表达式 box.corner.x 的意思是,前往 box 所引用的对象 (box本身是一个实例), 找到 corner 的属性 ; 然后前往corner所引用的对象,找到叫做 x 的属性.
复制
别名会降低程序的可读性, 因为一个地方的变动可能对另一个地方造成预料之外的影响.跟踪所有引用同一个对象的变量是非常困难的.
通常用复制对象的方法取代为对象起别名 .
浅复制
copy 模块拥有一个叫做copy的函数,可以复制任何对象.
>>> p1 = Point()
>>> p1.x = 3.0
>>> p1.y = 4.0
>>> import copy
>>> p2 = copy.copy(p1)
>>> print_point(p1)
(3, 4)
>>> print_point(p2)
(3, 4)
>>> p1 is p2
False
>>> p1 == p2
False
is 运算符用来判断两者是否为同一个对象,结果正如我们所料! 不过 == 的结果也是False,这是为什么呢 ? == 运算符默认检查的是对象的标示是否相同,而非对象的值是否相同.
深复制
copy 模块拥有一个叫做deepcopy的函数,可以复制任何对象.
>>> box2 = copy.copy(box) # 其中box是一个 Rectangle 的实例
>>> box2 is box
False
>>> box2.corner is box.corner
True
>>> box3 = copy.deepcopy(box)
>>> box3 is box
False
>>> box3.corner is box.corner
False
你会发现,当使用浅复制的时候,它仅仅复制了Rectangle对象,但没有复制嵌套的Point对象.
- 用 isinstance 来检查某个对象是不是某个类的实例
>>> isinstance(p,Point)
True
- 用hasattr 来检查一个对象是否有某个属性
>>> hasattr(p,'x')
True
字典中的键映射多个值
怎样实现一个键对应多个值的字典 ?
经典的是:一个字典就是一个键对应一个单值的映射.如果想要映射多个值,那么你就需要将这多个值放在另外的容器中,比如列表或者集合.
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)
但有一点你需要注意: defaultdict 会自动为将要访问的键(就算目前字典中没有这样的键)创建映射实体, 比如访问一个不存在的键,值是一个空的集合或者列表,具体是什么,取决于你自己传进去的是list 还是set
对比一下传统的和用defaultdict的初始化字典的区别 , 高下立判.
d = {}
for key , value in pairs:
if key not in d:
d[key] = []
d[key].append(value)
d = defaultdict(list)
for key,value in pairs:
d[key].append(value)
字典排序
为了能控制一个字典中元素的顺序,你可以使用 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])
字典的运算
如何在数据字典中执行一些计算操作(比如求最小值/最大值/排序)等?
通常与zip () 函数一起使用 . 将字典的键与值翻转过来 (可以用sorted函数直接对数据进行排序).
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')
#使用sorted 和 zip 来排序字典数据
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')]
note : zip()函数创建的是一个只能访问一次的迭代器.
怎样在两个字典中寻找相同点(比如相同的键/相同的值) ?
为了寻找两个字典的相同点 , 可以简单的在两字典的keys() 或者 items() 方法返回结果上执行集合操作 .
a = {
'x' : 1,
'y' : 2,
'z' : 3
}
b = {
'w' : 10,
'x' : 11,
'y' : 2
}
In [34]: a.keys() & b.keys() # 交集
Out[34]: {'x', 'y'}
In [35]: a.keys() | b.keys() # 并集
Out[35]: {'w', 'x', 'y', 'z'}
In [36]: a.items() & b.items() # 交集
Out[36]: {('y', 2)}
加入你想以现有字典构造一个排除几个指定键的新字典 . 下面利用李彪推导来实现这样的要求 .
# Make a new dictionary with certain keys removed
c = {key:a[key] for key in a.keys() - {'z', 'w'}}
# c is {'x': 1, 'y': 2}
note : 进行集合操作时,要用集合的数据结构 . 也就是 { } .