构造一个1, 3, 5, 7, ..., 99
的列表,可以通过循环实现:
L = [] n = 1 while n <= 99: L.append(n) n = n + 2
切片
取一个list或tuple的部分元素是非常常见的操作。
>>> L = [‘Michael‘, ‘Sarah‘, ‘Tracy‘, ‘Bob‘, ‘Jack‘] #取前3个元素 >>> [L[0], L[1], L[2]] [‘Michael‘, ‘Sarah‘, ‘Tracy‘] #取前N个元素,也就是索引为0-(N-1)的元素,可以用循环: >>> r = [] >>> n = 3 >>> for i in range(n): ... r.append(L[i]) ... >>> r [‘Michael‘, ‘Sarah‘, ‘Tracy‘]
对这种经常取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice)操作符,能大大简化这种操作。
对应上面的问题,取前3个元素,用一行代码就可以完成切片:
>>> L[0:3] [‘Michael‘, ‘Sarah‘, ‘Tracy‘]
L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。索引0可以省略。
>>> L[-2:] [‘Bob‘, ‘Jack‘] >>> L[-2:-1] [‘Bob‘]
>>> L = range(100) #创建一个0-99的数列 >>> L [0, 1, 2, 3, ... ,98, 99] >>> L[:10] #取前10个数 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> L[-10:] #取后10个数 [90, 91, 92, 93, 94, 95, 96, 97, 98, 99] >>> L[10:20] #取第11-20个数 [10, 11, 12, 13, 14, 15, 16, 17, 18, 19] >>> L[:10:2] #在前10个数中每2个取一个 [0, 2, 4, 6, 8] >>> L[::5] #在所以数里每5个取一个 [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95] >>> L[:] #显示整个数列 [0, 1, 2, 3, ... ,98, 99]
tuple和字符串切片:
>>> (0, 1, 2, 3, 4, 5)[:3] (0, 1, 2) >>> ‘ABCDEFG‘[:3] ‘ABC‘ >>> ‘ABCDEFG‘[::3] ‘ADG‘
迭代
当我们使用for
循环时,只要作用于一个可迭代对象,for
循环就可以正常运行。
如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:
>>> from collections import Iterable >>> isinstance(‘abc‘, Iterable) True >>> isinstance([1, 2, 3], Iterable) True >>> isinstance(123, Iterable) False
dict迭代:
>>> d = {‘a‘: 1, ‘b‘: 2, ‘c‘: 3} #dict迭代是key >>> for key in d: ... print key ... a c b >>> for value in d.itervalues(): #value迭代 ... print value ... 1 3 2 >>> for k, v in d.iteritems(): #key和value同时迭代 ... print k, v ... a 1 c 3 b 2
Python内置的enumerate
函数可以把一个list变成索引-元素对,这样在for
循环中可以同时迭代索引和元素本身:
>>> for i, value in enumerate([‘A‘, ‘B‘, ‘C‘]): ... print i, value ... 0 A 1 B 2 C #for循环中的两个变量使用 >>> for x, y in [(1, 1), (2, 4), (3, 9)]: ... print x, y ... 1 1 2 4 3 9
任何可迭代对象都可以作用于for
循环,包括我们自定义的数据类型,只要符合迭代条件,就可以使用for
循环。
列表生成式
列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
可以用range(1, 11)
:
>>> range(1, 11) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
生成[1*1, 2*2, 3*3, ... , 10*10]:
方法一:for循环
>>> L = [] >>> for x in range(1, 11): ... L.append(x * x) ... >>> L [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
方法二:列表生成式
>>> [x * x for x in range(1, 11)] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
#判断偶数 >>> [x * x for x in range(1, 11) if x % 2 == 0] [4, 16, 36, 64, 100] #两层循环 >>> [m + n for m in ‘ABC‘ for n in ‘XYZ‘] [‘AX‘, ‘AY‘, ‘AZ‘, ‘BX‘, ‘BY‘, ‘BZ‘, ‘CX‘, ‘CY‘, ‘CZ‘]
列出当前目录下的所有文件和目录名:
>>> import os # 导入os模块 >>> [d for d in os.listdir(‘.‘)] #os.listdir可以列出文件和目录 [‘.cshrc‘, ‘test.py‘, ‘.pki‘, ‘.viminfo‘, ‘.npm‘, ‘.bash_history‘, ‘.bash_logout‘, ‘.cache‘, ‘test.html‘, ‘.bashrc‘, ‘install.log‘, ‘.bash_profile‘, ‘.ssh‘, ‘.tcshrc‘, ‘anaconda-ks.cfg‘, ‘tmp‘, ‘install.log.syslog‘, ‘tomcat_install.sh‘, ‘.ansible‘]
for
循环其实可以同时使用两个甚至多个变量,比如dict
的iteritems()
可以同时迭代key和value:
>>> d = {‘x‘: ‘A‘, ‘y‘: ‘B‘, ‘z‘: ‘C‘} >>> for k, v in d.iteritems(): ... print k, ‘=‘, v ... y = B x = A z = C
列表生成式同样可以做到:
>>> d = {‘x‘: ‘A‘, ‘y‘: ‘B‘, ‘z‘: ‘C‘} >>> [k + ‘=‘ + v for k, v in d.iteritems()] [‘y=B‘, ‘x=A‘, ‘z=C‘]
改变字符串大小写:
>>> L = [‘Hello‘, ‘world‘, ‘IBM‘, ‘Apple‘] >>> [s.lower() for s in L] [‘hello‘, ‘world‘, ‘ibm‘, ‘apple‘]
isinstance
函数可以判断一个变量是不是字符串:
>>> x = ‘abc‘ >>> y = 123 >>> isinstance(x, str) True >>> isinstance(y, str) False >>> isinstance(y, int) True
通过添加if
语句保证列表生成式能正确地执行:
>>> L = [‘Michael‘, ‘Jim‘, 13, ‘Bob‘, ‘Hello World‘, None] >>> [s.lower() if isinstance(s, str) else s for s in L] [‘michael‘, ‘jim‘, 13, ‘bob‘, ‘hello world‘, None]
生成器
在Python中,一边循环一边计算的机制,称为生成器(Generator)。
方法:
第一种:把一个列表生成式的[]
改成()
,就创建了一个generator:
>>> L = [x * x for x in range(10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x * x for x in range(10)) >>> g <generator object <genexpr> at 0x7fa74c03b5a0> >>> g.next() #逐个打印内部每个元素 0 >>> g.next() 1 >>> g.next() 4 >>> g.next() 9 >>> g = (x * x for x in range(10)) #for循环调用(generator是可迭代对象) >>> for n in g: ... print n ... 0 1 4 9 16 25 36 49 64 81
第二种:如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator:
复杂的裴波拉契数列(Fibonacci)(除第一个和第二个数外,任意一个数都可由前两个数相加得到):
>>> def fib(max): #列表生成式无法写出裴波拉契数列,可以定义函数打印出来 ... n, a, b = 0, 0, 1 ... while n < max: ... print b ... a, b = b, a + b ... n = n + 1 ... >>> fib(6) #打印前6位数字 1 1 2 3 5 8
fib
函数定义了斐波拉契数列的推算规则,从第一个元素开始推算出后续任意的元素,这种逻辑其实非常类似generator。
要把fib
函数变成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 ... >>> fib(6) <generator object fib at 0x104feaaa0>
但是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。
在上述例子中,我们在循环过程中不断调用yield
,就会不断中断。
把函数改成generator后,我们基本上从来不会用next()
来调用它,而是直接使用for
循环来迭代:
>>> for n in fib(7): ... print n ... 1 1 2 3 5 8 13
generator的工作原理:它是在for
循环的过程中不断计算出下一个元素,并在适当的条件结束for
循环。