python高级特性

来源:互联网 发布:vr unity3d 比ue4清晰 编辑:程序博客网 时间:2024/06/08 15:29

1. 切片

取一个list或tuple的部分元素是非常常见的操作。对这种经常取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice)操作符,能大大简化这种操作。

>>> L = ['Michael', 'Sarah','Tracy', 'Bob', 'Jack']

>>> L[0:3]

['Michael', 'Sarah', 'Tracy']

L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。

如果第一个索引是0,还可以省略:

>>> L[:3]

['Michael', 'Sarah', 'Tracy']

也可以从索引1开始,取出2个元素出来:

>>> L[1:3]

['Sarah', 'Tracy']

类似的,既然Python支持L[-1]取倒数第一个元素,那么它同样支持倒数切片

>>> L[-2:]

['Bob', 'Jack']

>>> L[-2:-1]

['Bob']

记住倒数第一个元素的索引是-1。-2:后面为空,表示从-2一直读到最后一个。

而-2:-1是从倒数第二个开始读,读到倒数第一个之前,也即只读倒数第二个。

2. 切片的应用

先创建一个0-99的数列:

>>> L = list(range(100))

>>> L

[0, 1, 2, 3, ..., 99]

可以通过切片轻松取出某一段数列。比如前10个数:

>>> L[:10]

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

后10个数:

>>> L[-10:]

[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

前11-20个数:

>>> L[10:20]

[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

前10个数,每两个取一个:

>>> L[:10:2]

[0, 2, 4, 6, 8]

所有数,每5个取一个:

>>> L[::5]

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

甚至什么都不写,只写[:]就可以原样复制一个list:

>>> L[:]

[0, 1, 2, 3, ..., 99]

tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple:

>>> (0, 1, 2, 3, 4, 5)[:3]

(0, 1, 2)

字符串'xxx'也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串:

>>> 'ABCDEFG'[:3]

'ABC'

>>> 'ABCDEFG'[::2]

'ACEG'

3. 迭代

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

list这种数据类型虽然有下标,但很多其他数据类型是没有下标的,但是,只要是可迭代对象,无论有无下标,都可以迭代,比如dict就可以迭代:

>>> d = {'a': 1, 'b': 2, 'c': 3}

>>> for key in d:

        print(key)

a

c

b

因为dict的存储不是按照list的方式顺序排列,所以,迭代出的结果顺序很可能不一样。

默认情况下,dict迭代的是key。如果要迭代value,可以用forvalue in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()。由于字符串也是可迭代对象,因此,也可以作用于for循环:

>>> for ch in 'ABC':

       print(ch)

A

B

C

4. 判断可迭代对象

通过collections模块的Iterable类型判断:

>>> from collections import Iterable

>>> isinstance('abc', Iterable) #str是否可迭代

True

>>> isinstance([1,2,3], Iterable) #list是否可迭代

True

>>> isinstance(123, Iterable) # 整数是否可迭代

False

5. list的下标形式循环

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

>>> for i, value in enumerate(['A','B', 'C']):

      print(i, value)

0 A

1 B

2 C

6. 列表生成式

列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

生成[1x1, 2x2, 3x3, ...,10x10]:

>>> [x * x for x in range(1, 11)]

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来。

for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:

>>> [x * x for x in range(1, 11) ifx % 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']

7. 列表生成式的应用

运用列表生成式,可以写出非常简洁的代码。例如,列出当前目录下的所有文件和目录名,可以通过一行代码实现:

>>> import os # 导入os模块

>>> [d for d in os.listdir('.')] #os.listdir可以列出文件和目录

['.emacs.d', '.ssh', '.Trash', 'Adlm','Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies','Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode']

表生成式也可以使用两个变量来生成list:

>>> d = {'x': 'A', 'y': 'B', 'z':'C' }

>>> [k + '=' + v for k, v ind.items()]

['y=B', 'x=A', 'z=C']

最后把一个list中所有的字符串变成小写:

>>> L = ['Hello', 'World', 'IBM','Apple']

>>> [s.lower() for s in L]

['hello', 'world', 'ibm', 'apple']

8. isinstance函数

isinstance函数可以判断一个变量是不是字符串:

>>> x = 'abc'

>>> y = 123

>>> isinstance(x, str)

True

>>> isinstance(y, str)

False

8. 生成器

如果列表元素可以按照某种算法推算出来,就可以在循环的过程中不断推算出后续的元素不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个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> at0x1022ef630>

创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。

把generator的每一个元素一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

>>> next(g)

0

>>> next(g)

1

generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

可以使用for循环得到每个元素,因为generator也是可迭代对象:

>>> g = (x * x for x in range(10))

>>> for n in g:

              print(n)

所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

9. 斐波拉契数列

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

def fib(max):

    n,a, b = 0, 0, 1

   while n < max:

       print(b)

       a, b = b, a + b

       n = n + 1

   return 'done'

上面的函数可以输出斐波那契数列的前N个数:

>>> fib(6)

1

1

2

3

5

8

'done'

要把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

   return 'done'

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

>>> for n in fib(6):

              print(n)

10. 杨辉三角

         1

       1   1

     1   2   1

   1   3   3   1

 1   4   6  4   1

1  5   10  10 5   1

把每一行看做一个list,写一个generator,不断输出下一行的list:

def triangles(max):

    L =[1]

   while n < max:

       yield L

       L = [1] + [L[i]+L[i+1]for i in range(len(L)-1)] + [1]

n = 0

for t in triangles(10):

   print(t)

    n =n + 1

    ifn == 10:

       break

11. 迭代器

可以直接作用于for循环的数据类型有以下几种:一类是集合数据类型,如list、tuple、dict、set、str等;一类是generator,包括生成器和带yield的generator function。这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以使用isinstance()判断一个对象是否是Iterable对象。

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

可以使用isinstance()判断一个对象是否是Iterator对象:

>>> from collections import Iterator

>>> isinstance((x for x inrange(10)), Iterator)

True

>>> isinstance([], Iterator)

False

>>> isinstance({}, Iterator)

False

>>> isinstance('abc', Iterator)

False

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。把list、dict、str等Iterable变成Iterator可以使用iter()函数:

>>> isinstance(iter([]), Iterator)

True

>>> isinstance(iter('abc'),Iterator)

True

Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

12. 生成器、迭代器总结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

原创粉丝点击