我们来介绍Python中非常有用的高级特性,一行代码能实现的功能,决不写5行代码
切片
切片(Slice)操作符
L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。
只写[:]就可以原样复制一个list
如果第一个索引是0,还可以省略:
L[:3]
倒数切片
L[-2:] 倒数第2个至倒数第1个
记住倒数第一个元素的索引是-1
a[::-1] 将列表倒过来
字符串’xxx’或Unicode字符串u’xxx’也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串
在很多编程语言中,针对字符串提供了很多各种截取函数,其实目的就是对字符串切片。Python没有针对字符串的截取函数,只需要切片一个操作就可以完成,非常简单。
前段时间Jeff Atwood 推广了一个简单的编程练习叫FizzBuzz,问题引用如下: 写一个程序,打印数字1到100,3的倍数打印“Fizz”来替换这个数,5的倍数打印“Buzz”,对于既是3的倍数又是5的倍数的数字打印“FizzBuzz”。 这里有一个简短的方法解决这个问题:
for x in range(101):print”fizz”[x%3_4::]+”buzz”[x%5_4::]or x
print后面分为两部分,第一部分是”fizz”[x%3_4::]+”buzz”[x%5_4::],第二部分是x。两部分使用逻辑或连接。如果第一部分为空,则最终结果为第二部分的结果。如果第一部分非空,则最终结果为第一部分。
第一部分由两个字符串连接而成,第一个字符串为”fizz”[x%3_4::],如果x是3的倍数,则x%3=0,那么”fizz”[x%3_4::]=”fizz”[0::]=”fizz”;如果x不是3的倍数,则x%3=1或2,那么”fizz”[x%34::]=”fizz”[4::]或”fizz”[8::]=””。
第二个字符串为”buzz”[x%5_4::],如果x是5的倍数,那么”buzz”[x%5_4::]=”buzz”[0::]=”buzz”;如果x不是5的倍数,那么x%5=1,2,3,4,那么”buzz”[x%54::]=”buzz”[4::]或”buzz”[8::]或”buzz”[12::]或”buzz”[16::]或”buzz”[20::]=””
由此,如果x是3的倍数,第一部分为”fizz”;如果x是5的倍数,第一部分为”buzz”;如果x既是3的倍数,又是5的倍数,则第一部分为”buzzfizz”,如果既不是3的倍数,也不是5的倍数,则第一部分为””。
迭代
如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)
Python的for循环抽象程度要高于Java的for循环,因为Python的for循环不仅可以用在list或tuple上,还可以作用在其他可迭代对象上
关键是要有一个可迭代对象
如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断
from collections import Iterable
isinstance('abc', Iterable)
Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身
任何可迭代对象都可以作用于for循环,包括我们自定义的数据类型,只要符合迭代条件,就可以使用for循环。
列表 生成式
d = {‘x’: ‘A’, ‘y’: ‘B’, ‘z’: ‘C’ } [k + ‘=’ + v for k, v in d.items()] [‘y=B’, ‘x=A’, ‘z=C’] L = [‘Hello’, ‘World’, ‘IBM’, ‘Apple’] [s.lower() for s in L] [‘hello’, ‘world’, ‘ibm’, ‘apple’]
使用内建的isinstance函数可以判断一个变量是不是字符串
upper2 = [‘HelloBang’, 19, ‘World’, ‘IBM’, ‘Apple’]
lower2 = [s.lower() for s in upper2 if isinstance(s,str)] //会自动将不是str的值过滤掉
lower2 = [s.lower() if isinstance(s,str) else s for s in upper2 ] //不是str的值还会不变,不会被过滤
- 在一个列表生成式中,for前面的if … else是表达式,而for后面的if是过滤条件,不能带else
生成器
在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。
创建一个generator的两种方法
- 只要把一个列表生成式的[]改成()
- g = (x * x for x in range(10))
- for n in g:
… print(n) - yield关键字
- 如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator
- 案例: 斐波拉契数列
这里,最难理解的就是generator和函数的执行流程不一样。
- 函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
- 而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。
迭代器
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列(如上面讲到的生成器);
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。