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循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是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。

猜你喜欢

转载自www.cnblogs.com/xjmlove/p/9090258.html