3 高级特性
3.1 切片
切片使用方法list[start,end,step]
start
:起始位置end
:终止位置,但不包括end下标的值step
:步进
取一个list或tuple的部分元素是常见的现象,比如,一个list如下:
>>>L=['Mac','Iphone','Nokia','Huawei','OPPO']
取前三个数:
>>>L[0:3]
['Mac', 'Iphone', 'Nokia']
上述就是切片操作,L[0:3]
表示从索引0开始,直到索引3结束,但不包含索引3位置的值。
当索引为0时,可以省略L[:3]
列出所有的值:L[:]
既然索引可以从-1开始,类似,取倒数的值也是可以的:
>>> L[-3:-1]
['Nokia', 'Huawei']
记住:倒数第一个数的索引是-1
tuple
也是一种list,也可以使用切片,操作的结果也是个tuple
3.2 迭代
如果给定一个list
或tuple
,我们可以通过for
循环遍历这个list
或tuple
,这种遍历我们称之为迭代(Iteration)。
在Python中,迭代是通过for...in...
来完成的。list虽然这种类型有下标,但是也有很多数据类型没有下标,比如dict
,但是只要是可迭代对象,无论有无下标,都可以迭代。
那么,如何判断一个对象是可迭代对象呢?方法是通过Collections
模块的Iterable类型判断:
>>>from collections import Iterable
>>>isinstance('abc', Iterable) #str是否可迭代
True
>>> isinstance(222,Iterable) #整数不可迭代
False
如果要对list
实现类似java那样的下标循环,可以使用enumerate
函数,把list
变成索引-元素对。这样就可以使用for循环中同时迭代索引和元素本身:
>>>for i,value in enumerate(['Mac','Iphone','Nokia','Huawei','OPPO']):
... print(i,value)
0 Mac
1 Iphone
2 Nokia
3 Huawei
4 OPPO
上面的for
循环,可以同时引用两个变量,在Python中是很常见的:
>>>for x,y in [(1,'a'),(2,'b'),(3,'c')]:
...print(x,y)
...
1 'a'
2 'b'
3 'c'
3.3 列表生成式
列表生成式即List Comprehensions,是Python内置的非常简单但强大的可以创建List的生成式。
举例:要生成list [1,2,3,4,5,6,7,8],可以使用list(range(1,8))
>>> list(range(1,8))
[1, 2, 3, 4, 5, 6, 7]
但是要生成[1x1,2x2,3x3,…,7x7],则需要for
循环实现:
>>> L=[]
>>> L
[]
>>> for x in range(1,8): L.append(x*x)
...
>>> L
[1, 4, 9, 16, 25, 36, 49]
但是如此,代码比较繁琐。因此Python引入了列表生成式:
>>> [x*x for x in range(1,8)]
[1, 4, 9, 16, 25, 36, 49]
只需要一行代码,就可以实现。写列表生成式时,x*x
要写在前面,后面跟for
循环,就可以把列表创建出来。for
循环后面还可以跟if
判断,这样就可以筛选list
:
>>> [x*x for x in range(1,8) if x%2==0]
[4, 16, 36]
3.4 生成器
通过列表生成器,我们可以直接创建一个列表。但是,收到内存限制,列表容量是有限的。而且,创建一个包含100万个元素的数据,不仅占用内存很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面的元素占用的空间都白白浪费了。
如果列表元素可以按照某种算法计算出来,一边循环一边计算,在Python中,我们称之为生成器:gererator。
generator:
>>> L=[x*x for x in range(1,10)]
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g=(x*x for x in range(1,10))
>>> g
<generator object <genexpr> at 0x000001A73F646E60>
>>> next(g)
1
>>> next(g)
4
我们可以通过next(g)
获取generator的下一个返回值。直到计算最后一个元素的值,如果没有更多的元素,会报StopIteration
的错误。当我们创建一个generator
后,一般不用next()
函数计算下一个元素的值,而是用for
循环。
斐波那契数列(Fibonacci),很难用generator
生成器生成出来:
def fib(max):
n,a,b = 0,0,1
while n<=max:
print(b)
a,b = b,a+b
n = n + 1
return 'done'
上面的函数可以输出斐波那契数列的前N个数。可以看到,上面的函数跟generator
很接近了。如果要把该函数改造成generator
,只需要将print(b)
替换成yield b
:
def fib(max):
n,a,b = 0,0,1
while n<=max:
yield b
a,b = b,a+b
n = n + 1
return 'done'
关键字yield
:首先理解一下generator
函数执行过程,该过程跟函数的执行流程不一样,函数的执行顺序,遇到return
语句或者最后一行语句就返回。而generator
的函数,在每次调用next()
函数的时候执行,遇到yield
语句返回,再次执行时,从上次返回的yield
语句处继续执行。
3.5迭代器
可直接作用于for
循环的有两大类:
集合类数据类型,如
list
、tuple
、dict
、set
、str
等生成器(
generator
)
可迭代对象(Iterable
):可以从其获取到一个迭代器的任一对象,直接作用于for
循环的对象统称为可迭代对象。可以使用isinstance(object, classinfo)
判断一个对象是否为Interable
对象,比如:isinstance(list('abcde'), Interable)
迭代器(Iterator
):迭代器是那些允许你迭代可迭代对象的对象。可以被next()
函数调用不断返回下一个值的对象成为迭代器,可以使用isinstance()
判断一个对象是否为Iterator
对象,比如:isinstance((x for x in range(10)), Iterator)
注:与Iterable
的区别。
生成器(generator
)都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,但是可以使用Iter()
函数将Iterable
转换为Iterator
。
>>> isinstance(iter([]),Iterator)
True
>>> isinstance(iter('abc'),Iterator)
True
>>>
list、
tuple、
dict不是
Iterator,是因为Python中,
Iterator是一个数据流,
Iterator对象可以被
next()函数调用并返回下一个值,直到没有数据时,才会抛出
StopIteration。可以把这个数据流看成是一个有序序列,但我们无法直到序列的长度,只能通过不断的
next()函数实现按需计算下一个值,所以
Iterator`的计算是惰性的。只需要在返回下一个元素的时候,才会计算。
Iterator
可以是一个强大的数据流,比如:自然数。而list
是永远不可能存储自然数的。
小结:
凡是可以作用于
for
循环的都是Iterable
对象。凡是可以使用
next()
函数的都是Iterator
类型,它表示一个惰性计算的序列。集合数据类型如
list
、tuple
、dict
、set
、str
是Iterable
的,不过可以通过Iter()
函数转换为Iterator
对象。