python函数高级特性详解编程语言

1、切片

列表或元祖中取部分元素很常见。比如:

 

In [200]: list=['xjm','xyl','lxh','pzq'] 
In [201]: list[:3] 
Out[201]: ['xjm', 'xyl', 'lxh']

 

说明:这里我取了前三个,[:3]和[0:3]一样。0可省略

注意:索引是从零开始,以-1结束。

切片操作十分有用。我们来创建一个0–99的数列:

In [202]: l=list(range(0,100)) 
--------------------------------------------------------------------------- 
TypeError                                 Traceback (most recent call last) 
<ipython-input-202-7935b62f0794> in <module>() 
----> 1 l=list(range(0,100)) 
 
TypeError: 'list' object is not callable 
 
In [203]: del list 
 
In [204]: l=list(range(0,100))

说明:很明显看到报错了,因为list之前被赋值了。导致创建列表时,引用对象不存在。这时删除就行。

我们来取前20个数:

In [206]: l[:10] 
Out[206]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

 后十个数:

In [207]: l[-10:] 
Out[207]: [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

 

第20-30个数:

In [208]: l[19:30] 
Out[208]: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]

 

前十个数。步长为2:

In [209]: l[:10:2] 
Out[209]: [0, 2, 4, 6, 8]

 

所有数,步长为5:

In [210]: l[::5] 
Out[210]: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]

 

元祖tuple也类似:

In [211]: t=1,2,3,4,5,'xjm' 
In [212]: t[0:2] 
Out[212]: (1, 2)

 字符串也是如此:

In [213]: 'xjmloveyou'[:7] 
Out[213]: 'xjmlove'

2、迭代

如果给定一个list或tuple,我们可以通过for循环来遍历。这种遍历称为迭代。

In [225]: d=dict(a=1,b=2,c=3) 
 
In [226]: d 
Out[226]: {'a': 1, 'b': 2, 'c': 3} 
 
In [227]: for key in d: 
     ...:     print(key) 
     ...: 
a 
b 
c 
 
In [228]: for v in d.values(): 
     ...:     print(v) 
     ...: 
1 
2 
3 
 
In [229]: for k,v in d.items(): 
     ...:     print(k,v) 
     ...: 
a 1 
b 2 
c 3

 

说明:字典默认的是迭代key。如果要迭代value,可用d.values(),如果键值同时迭代。则可用d.items().

字符串也是可迭代对象。同样for循环:

In [230]: for char in 'xjm love you lalala': 
     ...:     print(char) 
     ...: 
x 
j 
m 
 
l 
o 
v 
e 
 
y 
o 
u 
 
l 
a 
l 
a 
l 
a

 

所以,当我们使用for循环时,只要作用于可迭代对象,for循环就可以运行,而我们不太关心该对象究竟是list还是其他数据类型。

那么,如何判断一个对象是可迭代对象呢?通过collection模块的iterable类型来判断:

In [231]: from collections import Iterable 
 
In [232]: isinstance('xjm',Iterable) 
Out[232]: True 
 
In [233]: isinstance('[1,2,3]',Iterable) 
Out[233]: True 
 
In [234]: isinstance(123,Iterable) 
Out[234]: False 
 
In [235]: isinstance(1,2,3,Iterable) 
--------------------------------------------------------------------------- 
TypeError                                 Traceback (most recent call last) 
<ipython-input-235-1ee68315817a> in <module>() 
----> 1 isinstance(1,2,3,Iterable) 
 
TypeError: isinstance expected 2 arguments, got 4 
 
In [236]: isinstance((1,2,3),Iterable) 
Out[236]: True

 

说明:字典,元祖,列表,字符串都是True。整数是False。

Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:

In [237]: for i,v in enumerate(['a','b','c']): 
     ...:     print(i,v) 
     ...: 
0 a 
1 b 
2 c

 

In [239]: for i,j in [(1,2),(3,4),(5,6)]: 
     ...:     print(i,j) 
1 2 
3 4 
5 6

 

In [240]: for i,j in [[1,2],[3,4],[5,6]]: 
     ...:     print(i,j) 
 
1 2 
3 4 
5 6

练习:请使用迭代查找一个list中最小和最大值,并返回一个tuple:

In [5]: def find(list): 
   ...:     if list !=[]: 
   ...:         max,min = list[0],list[0] 
   ...:         for i in list: 
   ...:             if max < i: 
   ...:                 max = i 
   ...:             if min > i: 
   ...:                 min = i 
   ...:         return(min,max) 
   ...:     else: 
   ...:         print('这是一个l空列表,无法比较') 
 
In [6]: find([1,2,3,4,5,6,7,8,9]) 
Out[6]: (1, 9) 
In [7]: find([]) 
这是一个l空列表,无法比较

 

3、列表生成式

举个例子,生成[1,2,3,4,5,6,7,8,9,10],可以用list(range(1,11))创建。

In [9]: list(range(1,11)) 
Out[9]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 

但是,如果要生成[1,4,9,16,25,36,49]这种列表呢?你应该想到了循环:

In [10]: list=[] 
In [12]: for i in range(1,8): 
    ...:     list.append(i**2) 
    ...: 
 
In [13]: list 
Out[13]: [1, 4, 9, 16, 25, 36, 49]

 

太繁琐啦,有没有简单快速的方法呢?如下:

In [14]: list=[x*x for x in range(1,8)] 
 
In [15]: list 
Out[15]: [1, 4, 9, 16, 25, 36, 49]

 

还可以用到lambda函数:

In [28]: res=map(lambda x:x*x,range(1,8))

In [29]: list(res)
Out[30]: [1, 4, 9, 16, 25, 36, 49]

 

这里我想错了,因为map在python2是直接返回一个列表,而python3是一个迭代对象。可以用list直接转。

还可以在后面加条件:

In [36]: [x*x for x in range(1,10) if x % 2==0] 
Out[36]: [4, 16, 36, 64]

 还可以使用两层循环,可以生成全排列:

In [37]: [x+y for x in "abc" for y in"ABC"] 
Out[37]: ['aA', 'aB', 'aC', 'bA', 'bB', 'bC', 'cA', 'cB', 'cC']

 

把列表的字符串全变为小写:

In [38]: l=['Hello','world','IBM','Google'] 
In [39]: a=[s.lower() for s in l] 
In [40]: a 
Out[40]: ['hello', 'world', 'ibm', 'google']

4、生成器

通过列表生成式可以直接创建一个列表,但是毕竟内存有限制,容量有限。所以有一种边循环边计算的机制,称为生成器:generator.

创建generator:

把列表生成式的方括号改为括号就行啦!

In [45]: g=(x*x for x in (1,2,3)) 
 
In [46]: type(g) 
Out[46]: generator 
 
In [47]: next(g) 
Out[47]: 1 
 
In [48]: next(g) 
Out[48]: 4 
 
In [49]: next(g) 
Out[49]: 9

 

说明:当没有下一个元素时,跑出StopIteration的异常。

其实,generator也是一个可迭代对象,所以可以通过for循环。

In [56]: for i in g: 
    ...:     print(i) 
 
1 
4 
9

 

下面来打印一下fbi:

In [60]: def fbi(max): 
    ...:     n,a,b=0,0,1 
    ...:     while n<max: 
    ...:         print(b) 
    ...:         a,b=b,a+b 
    ...:         n+=1 
    ...:     return 'done' 
    ...: 
 
In [61]: fbi(1) 
1 
Out[61]: 'done' 
 
In [62]: fbi(8) 
1 
1 
2 
3 
5 
8 
13 
21 
Out[62]: 'done'

 

要想把这种逻辑变成generator。只要把print改成yield就可以了,就不再是普通函数,而是一个generator。

简单例子,依次返回数字1,3,5:

In [63]: def odd(): 
    ...:     yield 1 
    ...:     yield 2 
    ...:     yield 3 
    ...: 
 
In [64]: o=odd() 
 
In [65]: o 
Out[65]: <generator object odd at 0x000001798E9FEA40>

 

然后用next取值:

In [66]: next(o) 
Out[66]: 1 
 
In [67]: next(o) 
Out[67]: 2 
 
In [68]: next(o) 
Out[68]: 3

 

回到之前的fib。我们可以使用下面代码来实现:

In [82]: g=fbi(6) 
 
In [83]: while True: 
    ...:     try: 
    ...:         x=next(g) 
    ...:         print('g',x) 
    ...:     except StopIteration as e: 
    ...:         print('结束取值',e.value) 
    ...:         break 
    ...: 
g 1 
g 1 
g 2 
g 3 
g 5 
g 8 
结束取值 done

 

5、迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如list、tuple、dict、set、str等;

一类是generator,包括生成器和带yield的generator 函数。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以用isinstance()来判断。

而生成器不但可以作用于for循环,还可以被next()取值。

Iterable变成Iterator可以使用iter()函数:

In [85]: isinstance(iter([1,2,3]),Iterator) 
Out[85]: True

 

总结:

  • 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
  • 可以使用isinstance()判断一个对象是否是Iterator对象和Iterable。

 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/7557.html

(0)
上一篇 2021年7月18日
下一篇 2021年7月18日

相关推荐

发表回复

登录后才能评论