记得曾经在学Java的时候,通常是这么学的,从基础的语法高级特性,这一块统称为JavaSE,然后再到JavaWeb,最后到框架这一块。那么Python也有其对应的高级特性。其实在聪哥哥我看来,无论任何编程语言,基本都是这一套。只不过每个编程在其特有的领域有其特定的优势。比如拿区块链来说,其实Java也可以做。只不过没有Python或者是Go做起来相对那么轻松。

再比如Java可以用于开发客户端应用、网页端(web应用)等等,同样Python也可以。

今天聪哥哥说高级特性,主要围绕这么几个方面?

(1)切片;

(2)迭代;

(3)列表生成式;

(4)生成器;

(5)迭代器;

一、切片

切片这个玩意不好用语言来表达,不过聪哥哥我还是得说一下。

经常取指定范围的索引叫做切片,一听切片切片,肯定是切一个整体的某一部分。

没有切片之前,我们是怎么取数据的

示例一(取前三个数据):

# -*- coding: utf-8 -*-
L = ['A', 'B', 'C', 'D', 'E']
print([L[0], L[1], L[2]])

通过L[0]这种方式去取,感觉很麻烦是不是,或许有人说,写个for循环直接遍历就行。那么如果是比遍历的话,就需要加对应的判断代码,因为我需要的是某一段数据值,遍历还是太麻烦了。

不过别怕,Python高级特性之一的切片即能做到非常的简化,又能达到对应的目的。

示例二:

# -*- coding: utf-8 -*-
L = ['A', 'B', 'C', 'D', 'E']
print(L[:3])

示例一和示例二的效果是一样的,但是示例二比示例一更简化。

L[:3] 所代表的就是初索引为0,往前取三个值。如果初索引不为0,你就需要指定,例如L[1:3]这样的。

 

二、迭代

什么是迭代?

引用百度百科:

迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。

重复执行一系列运算步骤,从前面的量依次求出后面的量的过程。此过程的每一次结果,都是由对前一次所得结果施行相同的运算步骤得到的。例如利用迭代法*求某一数学问题的解。

对计算机特定程序中需要反复执行的子程序*(一组指令),进行一次重复,即重复执行程序中的循环,直到满足某条件为止,亦称为迭代。

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

示例一:

# -*- coding: utf-8 -*-
d = {'a': 1, 'b': 2, 'c': 3}
for key in d:
	print(key)

 

这里或许会有人疑问,如何判断这个对象是可迭代的?

通过collections模块的Iterable类型判断

示例二(如何判断这个对象是可迭代的):

# -*- coding: utf-8 -*-
from collections import Iterable
print(isinstance('abc', Iterable))

当最终输出的结果为True,就表示这个对象是可迭代的。

任何可迭代对象都可以作用于for循环,包括我们自定义的数据类型,只要符合迭代条件,就可以使用for循环

 

三、列表生成式

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

举例说明:要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用list(range(1, 11))

 

原来我们是怎么做的?

示例一:

# -*- coding: utf-8 -*-
print(list(range(1, 11)))

数据范围比较小还行,如果换成这样:

要生成[1x1, 2x2, 3x3, ..., 10x10]这样的,怎么做?

肯定是要用到循环的。

示例二:

# -*- coding: utf-8 -*-
L = []
for x in range(1, 11):
   L.append(x * x)
print(L)

但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上面的list:

示例三:

# -*- coding: utf-8 -*-
print([x * x for x in range(1, 11)])

示例三同示例二的效果是一样的,但是从简洁性来看似乎示例三稍微比for循环要好点。或许有人说:我觉得还是for循环好,这里了也看不出比for循环好在那。聪哥哥我也不能说的太细,说的太细,过于高深,反而讲偏。一句话:仁者见仁,智者见智。

接下来可能有人会骂我说。好吧,我只能硬着头皮说说呢,就拿L.append说事,每次追加数据,都相当于添加一个地址和引用会有一定的内存开销。少的数据还好,如果是大数据呢。

 

再比如使用列表生成式可以使代码更简洁,例如我要获取当前目录下的所有文件:

示例四:

# -*- coding: utf-8 -*-
import os
print([d for d in os.listdir('.')])

聪哥哥有话说:运用列表生成式,可以快速生成list,可以通过一个list推导出另一个list,而代码却十分简洁。

 

四、生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

示例(简单示例):

# -*- coding: utf-8 -*-
g = (x * x for x in range(10))
for n in g:
    print(n)

聪哥哥有话说:

generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

 

五、迭代器

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

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

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

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

示例一:

# -*- coding: utf-8 -*-
from collections import Iterator
print(isinstance((x for x in range(10)), Iterator))

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator。

 

示例二(把listdictstrIterable变成Iterator可以使用iter()函数):

# -*- coding: utf-8 -*-
from collections import Iterator
print(isinstance(iter([]), Iterator))

你可能会问,为什么listdictstr等数据类型不是Iterator

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

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

最后聪哥哥有话说:

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

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

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