《Python编程》学习笔记1.1
本篇承接上文,介绍列表解析、生成器表达式和map的使用,这些都是python中的强大的迭代工具。
>>> pays = [person[2] for person in people] # 收集薪酬信息
>>> pays
[36000.0, 60000.0]
>>> pays = map((lambda x: x[2]), people) # 同上(map是3.x中的生成器)
>>> list(pays)
[36000.0, 60000.0]
>>> sum(person[2] for person in people) # 生成器表达式,sum为内建函数
96000.0
列表解析式可以取代内建的
map()
函数以及lambda
,而且效率更高。
列表解析介绍
它是根据已有列表,将之转换成另一个列表从而高效创建新列表的方式。
在转换过程中,可以指定元素必须符合一定的条件,才能添加至新的列表中,这样每个元素都可以按需要进行转换。
列表解析是Python迭代机制的一种应用,它常用于实现创建新的列表,因此用在[ ]中。
但它实际上是适用于任何可迭代对象的(iterable)。
List comprehension / Dict comprehension / Set comprehension / Generator comprehension
语法:
[expression for iter_val in iterable]
[expression for iter_val in iterable if cond_expr]
实例List comprehension:
要求:列出1~10所有数字的平方。
----------------------------------------------------
1、普通方法:
>>> L = []
>>> for i in range(1,11):
L.append(i**2)
>>> print(L)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
----------------------------------------------------
2、列表解析
>>>L = [i**2 for i in range(1,11)]
>>>print L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
要求:列出1~10中大于等于4的数字的平方。
-----------------------------------------------------
1、普通方法:
>>> L = []
>>> for i in range(1,11):
if i >= 4:
L.append(i**2)
>>> print(L)
[16, 25, 36, 49, 64, 81, 100]
-----------------------------------------------------
2、列表解析
>>>L = [i**2 for i in range(1,11) if i >= 4 ]
>>>print(L)
[16, 25, 36, 49, 64, 81, 100]
要求:实现两个列表中的元素逐一配对。
1、普通方法:
>>> L1 = ['x','y','z']
>>> L2 = [1,2,3]
>>> L3 = []
>>> for a in L1:
for b in L2:
L3.append((a,b))
>>> print(L3)
[('x', 1), ('x', 2), ('x', 3), ('y', 1), ('y', 2), ('y', 3), ('z', 1), ('z', 2), ('z', 3)]
-------------------------------------------------------------------------------------------
2、列表解析:
>>> L1 = ['x','y','z']
>>> L2 = [1,2,3]
>>> L3 = [ (a,b) for a in L1 for b in L2 ]
>>> print(L3)
[('x', 1), ('x', 2), ('x', 3), ('y', 1), ('y', 2), ('y', 3), ('z', 1), ('z', 2), ('z', 3)]
更多实例:Dict comprehension / Set comprehension / Generator comprehension
dict comprehension:
交换字典的key和value
>>> dt = {'A':1,'B':2}
>>> {value:key for key,value in dt.items()}
{1: 'A', 2: 'B'}
set comprehension:
>>> s = set([1,2,4])
>>> {i**i for i in s}
set([256, 1, 4])
generator comprehension:
>>> g = (a+2 for a in range(7))
>>> for i in g:
print(i)
2
3
4
5
6
7
8
不足: 列表解析得一个不足就是必须生成所有数据,用于创建整个列表。这可能对有大量数据的迭代有其负面效应。
解决方法:生成器表达式,通过结合列表解析和生成器解决了这个问题。
生成器表达式
通过列表解析,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。
在Python中,这种一边循环一边计算的机制,称为生成器:generator。将之与列表解析结合就是生成器表达式了。
生成器表达式并不真正地创建数字列表,而是返回一个生成器对象,此对象在每次计算出一个条目后,把这个条目"产生"(yield)出来。生成器表达式使用了"惰性计算"或称作"延时求值"的机制。
一般来说,序列过长,并且每次只需要获取一个元素时,应该考虑生成器表达式而不是列表解析。
语法:
(expression for iter_val in iterable)
(expression for iter_val in iterable if cond_expr)
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[ ]改成( ),就创建了一个generator。
实例:
>>> N = (i**2 for i in range(1,8))
>>> print(N)
<generator object <genexpr> at 0x7fe4fd0e1c30> #此处返回的是一个生成器的地址
>>> N.next()
1
>>> N.next()
4
>>> N.next()
9
>>> N.next()
16
>>> N.next()
25
>>> N.next()
36
>>> N.next()
49
>>> N.next() #所有元素遍历完后,抛出异常StopIteration
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
其他方法现在暂且不论。
迭代器
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
延迟计算或惰性求值 (Lazy evaluation)
迭代器不要求你事先准备好整个迭代过程中所有的元素。仅仅是在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合。
可迭代对象
迭代器提供了一个统一的访问集合的接口。只要是实现了__iter__()
或__getitem__()
方法的对象,就可以使用迭代器进行访问。
- 序列:字符串、列表、元组
- 非序列:字典、文件
- 自定义类:用户自定义的类实现了
__iter__()
或__getitem__()
方法的对象
创建迭代器对象
使用内建的工厂函数iter(iterable)
可以获取迭代器对象:
语法:
iter(collection) -> iterator
iter(callable,sentinel) -> iterator
实例展示:
使用对象内置的__iter__()
方法生成迭代器
>>>L1 = [1,2,3,4,5,6]
>>>I1 = L1.__iter__()
>>>print(I1)
<listiterator object at 0x7fe4fd0ef550> # 返回一个迭代器地址
>>> I1.next()
1
>>> I1.next()
2
>>> I1.next()
3
使用内置工厂函数生成迭代器
>>>L1 = [1,2,3,4,5,6]
>>>I1 = iter(L1)
>>>print(I1)
<listiterator object at 0x7fe4fd0ef550> # 返回一个迭代器地址
>>> I1.next()
1
>>> I1.next()
2
>>> I1.next()
3
说明:for循环可用于任何可迭代对象。
for循环开始时,会通过迭代协议传输给iter()内置函数,从而能够从迭代对象中获得一个迭代器,返回的对象含有需要的next()方法。