Open ShannonChenCHN opened 6 years ago
有了切片(Slice)操作,很多需要取指定索引范围的地方,就不再需要循环来实现了。Python的切片非常灵活,一行代码就可以实现很多行循环才能完成的操作。
L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
取前 3 个:
>>> L[0:3]
['Michael', 'Sarah', 'Tracy']
前 5 个中,每隔一个取一个
>>> L[:5:2]
['Michael', 'Tracy', Jack']
tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple。
T = (0, 1, 2, 3, 4, 5)
>>> T[:3]
(0, 1, 2)
字符串 'xxx'
也可以看成是一种 list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串。(不同于其他语言,Python 没有针对字符串的截取函数,只需要切片一个操作就可以完成)
>>> 'ABCDEFG'[:3]
'ABC'
>>> 'ABCDEFG'[::2]
'ACEG'
如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。
任何可迭代对象都可以作用于for循环,包括我们自定义的数据类型,只要符合迭代条件,就可以使用for循环。在Python中,迭代是通过for ... in来完成的。
默认情况下,dict迭代的是key。
d = {'a': 1, 'b': 2, 'c': 3}
for key in d:
print(key, ':', d[key])
for value in d.values():
print(value)
for key, value in d.items():
print(key, ':', value)
字符串也是可迭代对象:
for c in 'English':
print(c)
for num in [2, 56, 23]:
print(num)
# Python内置的enumerate函数可以把一个list变成索引-元素对
for i, value in enumerate([3, 56, 23]):
print(i, value)
for x, y in [(1, 1), (2, 3), (5, 8)]:
print(x, y)
如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:
from collections.abc import Iterable
print(isinstance('abc', Iterable))
print(isinstance([1, 2, 3], Iterable))
print(isinstance(123, Iterable))
列表生成式,是 Python 内置的非常简单却强大的可以用来创建 list 的生成式。
运用列表生成式,可以快速生成 list,可以通过一个 list 推导出另一个 list,而代码却十分简洁。
个人理解:列表生成式的作用有点类似于高阶函数,给定一个 list,提供一个变换操作或者筛选条件,生成一个新数组。
L1 = list(range(1, 11))
print(L1)
L2 = [x * x for x in range(1, 11)]
print(L2)
使用筛选条件:
L3 = [x * x for x in range(1, 11) if x % 2 == 0]
print(L3)
使用双循环:
L4 = [m + n for m in 'ABC' for n in 'XYZ']
print(L4)
使用两个变量来生成 list:
d = {'baidu': 'www.baidu.com', 'tencent': 'www.qq.com', 'amazon': 'www.amazon.com'}
[k + '=' + v for k, v in d.items()]
print(d)
大写转小写:
L5 = ['Hello', 'World', 'IBM', 'Apple']
L5_lower = [s.lower() for s in L5]
print(L5_lower)
打印当前目录下的所有文件名:
import os
ls = [d for d in os.listdir('.')]
print(ls)
在Python中,这种一边循环一边计算的机制,称为生成器(generator)。
[]
改成 ()
,就创建了一个生成器:g = (x * x for x in range(10))
print(g) # <generator object <genexpr> at 0x101240c00>
print(g.__next__())
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# 可以使用 for 循环遍历生成器,因为generator也是可迭代对象。
for n in g:
print(n)
可以使用 for 循环遍历生成器,因为generator也是可迭代对象。
yield
关键字的函数来创建生成器:def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b #
a, b = b, a + b
n = n + 1
if n > 2:
return
return 'done'
for i in fib(6):
print(i)
# 打印结果: 1 1 2
如果一个函数定义中包含 yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator。
在执行过程中,遇到 yield
就中断执行并返回,再次执行时从上次返回的 yield
语句处继续执行,直到已经没有yield
可以执行了,再调用 next(o)
就会报错。
next(g)
,就计算出 g 的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出 StopIteration
的错误。可以直接作用于 for 循环的数据类型有以下几种:
list
、tuple
、dict
、set
、str
等;yield
的 generator function。这些可以直接作用于for循环的对象统称为可迭代对象(Iterable)。
生成器不但可以作用于for循环,还可以被 next()
函数不断调用并返回下一个值,直到最后抛出StopIteration 错误表示无法继续返回下一个值了。
可以被 next()
函数调用并不断返回下一个值的对象称为迭代器(Iterator)。
isinstance()
判断一个对象是否是 Iterable
对象isinstance()
判断一个对象是否是 Iterator
对象next()
函数的对象都是 Iterator
类型,它们表示一个惰性计算的序列。iter()
函数获得一个Iterator对象。这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被 next()
函数调用并不断返回下一个数据,直到没有数据时抛出 StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以 Iterator 的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
跟 Objective-C 中实现 NSFastEnumeration
协议就可以支持快速枚举类似,在 Python 中,实现 iterator 协议的 __iter__
方法和 __next__
方法,即可让自定义类也具备 Iterator 特性:
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
... print(char)
...
m
a
p
s
日期:2018.07.10 周二