Python(3)高级特性


此文章参考廖雪峰大神的官网,地址:高级特性 - 廖雪峰的官方网站 (liaoxuefeng.com)

一、切片

  • 在python的使用中,对于列表、元组的元素取值是非常常见的,例如:
  • 注意:切片是顾头不顾尾的
>>> L = ["aaa","bbb","ccc","ddd"] 
>>> print(L) 
['aaa', 'bbb', 'ccc', 'ddd']

#如果想取前三个元素,可以这样:
>>> print(L[0],L[1],L[2])   
aaa bbb ccc

#也可以使用for循环:
>>> for i in range(3):
...     a.append(L[i])
... 
>>> print(a) 
['aaa', 'bbb', 'ccc']

#但是明显前两种方法都比较繁琐,所以,python提供了切片(Slice)操作符,这样在取指定元素时可以变得更加简单,例如:
>>> print(L[0:3])   #表示从第0个元素取到第3个元素,由于切片是顾头不顾尾的,所以是不包含第3个元素的,只取出了前三个元素
['aaa', 'bbb', 'ccc']
>>> print(L[:3])    #默认:前面从0开始
['aaa', 'bbb', 'ccc']

#有了切片这个方法后,就可以轻松取出一段元素,例如:
>>> L = list(range(100))   #python3需要把range转换成列表,python2可以直接使用range赋值,range(100)表示0-99,同样顾头不顾尾
>>> print(L) 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
>>> print(L[:])     #切片没有指定条件的话,会输出全部
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
>>> print(L[:10])   #取前10
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> print(L[10:20])  #取10-19
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> print(L[:-1])   #使用负数时,是从末尾开始算的,":-1"表示从0到末尾-1,所以是0-98
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98]
>>> print(L[-10:-1])  #取倒数10到倒数1
[90, 91, 92, 93, 94, 95, 96, 97, 98]
>>> print(L[-20:-10]) 
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89]
>>> print(L[-10:])    
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

#如果想每个5个取一个值的话,可以这样做:
>>> print(L[::5])    #表示每隔5个值取一个元素
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
  • 上面的是列表的取值案例,列表的切片最终输出的结果还是列表
  • python的切片还可以引用在其他数据类型上,如元组、字符串等,例如:
#元组
>>> T = (1,2,3,4,5)  
>>> print(T) 
(1, 2, 3, 4, 5)
>>> print(T[1:3]) 
(2, 3)
>>> print(T[-3:]) 
(3, 4, 5)

#字符串
>>> S = "ABCDEFG" 
>>> print(S) 
ABCDEFG
>>> print(S[4:]) 
EFG
>>> print(S[::3]) 
ADG
  • 在自己实践过之后可以发现,元组切片后的输出还是元组,同样字符串切片后还是字符串

  • 这里引用一个小案例,不使用strip函数,利用切片来去除首位的空格:

# -*- coding: utf-8 -*-
def trim(s):
    if s[:1] != ' ' and s[-1:] != ' ':
        return s
    elif s[:1] == ' ':
        return trim(s[1:])
    else:
        return trim(s[:-1])

if trim('hello  ') != 'hello':
    print('测试失败!')
elif trim('  hello') != 'hello':
    print('测试失败!')
elif trim('  hello  ') != 'hello':
    print('测试失败!')
elif trim('  hello  world  ') != 'hello  world':
    print('测试失败!')
elif trim('') != '':
    print('测试失败!')
elif trim('    ') != '':
    print('测试失败!')
else:
    print('测试成功!')

这段代码通过切片去判断首位是否有空格,有的话会再次调用函数,并且引用第1元素或第-1元素来去除空格,然后继续做判断,直至首尾没有空格

二、迭代

  • 首先要知道的是,通过for循环来遍历列表、元组、字符串等,这种遍历就称为迭代
  • 需要注意的是,python中的迭代是直接通过for in的这种方式来完成的,而其他语言,比如C语言中的迭代是通过下标完成的,即i++这种方式。并且python的for循环还可以使用在其他的可迭代的数据类型上
  • 除了列表、元组这种有下标的数据类型,python中的for循环还可以使用在其他没有下标的可迭代数据类型上,如字典:
>>> L = {"aaa":1,"bbb":2,"ccc":3} 
{'aaa': 1, 'bbb': 2, 'ccc': 3}
>>> for i in L:
...     print(i) 
... 
aaa
bbb
ccc

#但是直接这样循环的话,可以看到,只能取到字典的key,取不到value,取value的话可以这样:
>>> for i in L.values():   #利用values函数来取到value的值
...     print(i)
... 
1
2
3

#想要同时取key和value的话可以使用items函数:
>>> for x,y in L.items():
...     print(x,y) 
... 
aaa 1
bbb 2
ccc 3

要注意的是,因为字典的存储不是按照列表的方式顺序排列的,所以迭代出的结果有可能会不同

  • 其他类型的一些循环:
#字符串
>>> S = "ABCDEFG" 
>>> print(S)      
ABCDEFG
>>> for i in S:
...     print(i) 
... 
A
B
C
D
E
F
G

#元组
>>> T = (1,2,3,4) 
>>> for i in T:
...     print(i) 
... 
1
2
3
4

#列表
>>> L = [1,2,3,4] 
>>> for i in L: 
...     print(i) 
... 
1
2
3
4
  • 在上面的案例中,可以看出,for循环只要是使用于可迭代的数据类型,都可以正常运行,那怎么看是否是可迭代的数据类型呢,python提供了相应的方法:
>>> from collections.abc import Iterable    #导入collections.abc模块的Iterable方法
>>> isinstance('aaaa',Iterable) 
True  #True表示为可迭代的数据类型
>>> isinstance([1,2,3],Iterable) 
True
>>> isinstance((1,2,3),Iterable) 
True
>>> isinstance(S,Iterable)       
True
>>> isinstance(L,Iterable) 
True
>>> isinstance(T,Iterable) 
True
>>> isinstance({"aaa":1,"bbb":2},Iterable) 
True
  • 引用其他的一些小案例:
>>> L = [1,2,3,4,5]   
>>> for x,y in enumerate(L):  #使用enumerate函数可以输出“下标 + 元素”的格式
...     print(x,y) 
... 
0 1
1 2
2 3
3 4
4 5

#利用for循环来达到这种效果
>>> L = [(1,2),(3,4),(5,6)]  
>>> for x,y in L:
...     print(x,y) 
... 
1 2
3 4
5 6

#取列表中的最大值和最小值:
# -*- coding: utf-8 -*-
def findMinAndMax(L):
    if L == []:
        return (None,None)
    else:  
        min=L[0]
        max=L[0]
        for i in L:
            if i > max:
                max = i
            if i < min:
                min = i
    return (min,max) 

if findMinAndMax([]) != (None, None):
    print('测试失败!')
elif findMinAndMax([7]) != (7, 7):
    print('测试失败!')
elif findMinAndMax([7, 1]) != (1, 7):
    print('测试失败!')
elif findMinAndMax([7, 1, 3, 9, 5]) != (1, 9):
    print('测试失败!')
else:
    print('测试成功!')    
    
先创建一个参照数,然后循环列表依次对比参照数,从而取出最大值和最小值    

三、列表推导式

  • 列表推导式,也叫列表生成式,(List Comprehensions),是python内置的一个简单、强大的可以用来创建列表的生成式
  • 下面举一些简单的例子进行对比:
#使用普通的方式创建列表
>>> L = list(range(1,11)) 
>>> print(L) 
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

#如果要使用列表生成[1*1,2*2,3*3,...,10*10]这样的可以使用for循环
>>> N = []
>>> for i in L:
...     N.append(i*i)
... 
>>> print(N) 
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

#感觉还是有些繁琐,那使用列表推导式该怎么写呢:
>>> [i * i for i in L] 
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

#可以看出推导式明显比上面的普通方法更加简单、便捷,下面来解析一下这个推导式
[i * i for i in L] 
在我的理解中,其实就是直接操作列表的值,使用for循环去指定要操作的列表,把里面的值拿出来,然后直接在开头对值进行操作,从而达到想要的效果
    
#如果这个不是很好理解那么还可以换一个:
>>> L = ["Aaa","Bbb","Ccc"]
>>> [i.lower() for i in L] 
['aaa', 'bbb', 'ccc']
使用lower函数把字符变成小写

注意:列表推导式是创建一个新列表,不会修改原列表的元素

  • 在熟悉基本的列表推导式后,我们还可以使用if语句、多层for循环来创建列表推导式,例如:
#只想输出1-10的偶数
>>> L = list(range(11)) 
>>> print(L) 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> [i for i in L if i % 2 == 0] 
[0, 2, 4, 6, 8, 10]
可以发现if语句是写在末尾的,如果想要加else呢?就需要换一下位置了
>>> [i if i % 2 == 0 else -i for i in L] 
[0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10]
这个推导式的意思是除以二余零的直接输出,否则变成负数输出

#还可以使用多层for循环来进行交叉输出
>>> [x + y for x in "abc" for y in "efg" ] 
['ae', 'af', 'ag', 'be', 'bf', 'bg', 'ce', 'cf', 'cg']

>>> [x + y + i for x in "abc" for y in "efg" for i in "hij"] 
['aeh', 'aei', 'aej', 'afh', 'afi', 'afj', 'agh', 'agi', 'agj', 'beh', 'bei', 'bej', 'bfh', 'bfi', 'bfj', 'bgh', 'bgi', 'bgj', 'ceh', 'cei', 'cej', 'cfh', 'cfi', 'cfj', 'cgh', 'cgi', 'cgj']
但是一般只会用到两层循环,两层以上的就很少用了

注意:在列表推导式中,for后面跟的if是过滤条件,不能跟else否则会报错,而if..else是表达式,所以需要写在前面

  • 之前说过for循环只要是可迭代的数据类型都可以使用,那么同样的列表推导式也可以进行引用
#引用字典
>>> d = {"a":1,"b":2,"c":3} 
>>> [x + '=' + y for x,y in d.items()] 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
TypeError: can only concatenate str (not "int") to str
在引用字典时,发现报错了,原来是因为int类型导致的报错
>>> d = {"a":"1","b":"2","c":"3"}   #提前转变为字符串类型后就可以正常输出了
>>> [x + '=' + y for x,y in d.items()]
['a=1', 'b=2', 'c=3']

注意:在使用列表推导式时,要注意列表、元组、字典元素的数据类型,比如要使用lower函数转换大小写时,如果列表中元素有int类型的,那么就会报错,可以使用内建函数isinstance来判断一个变量是不是字符串,例如:

>>> L = ["Aaa","Bbb",111,222,"Ccc",None] 
>>> [ i.lower() for i in L]  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
AttributeError: 'int' object has no attribute 'lower'
这样会报错,所以可以加一个isinstance的过滤条件
>>> [ i.lower() for i in L if isinstance(i,str) == True] 
['aaa', 'bbb', 'ccc']

三、生成器(generator)

  • 通过上面的列表推导式,我们可以直接创建一个列表,但是列表的容量肯定是有限的,如果要创建一个100万个元素的列表,不仅会占用很大的存储空间,而且,如果说里面的元素有百分之90都用不到的话,那么就会浪费很大的空间,而生成器就可以解决这个问题

  • 生成器可以根据某个算法在循环过程中不断的推算后续的元素,这样就不用创建完整的列表,从而节省大量的空间,而这种一边循环一边生成的机制,就叫生成器==(generator)==

  • 下面是创建生成器的案例:

#创建生成器只需要把列表推导式的[]换成()即可:
>>> L = list(range(11)) 
>>> [ i * i for i in L] 
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> ( i * i for i in L) 
<generator object <genexpr> at 0x0000022979D4C0B0>
可以发现生成器不会直接输出结果

#输出生成器的结果,使用next()
>>> g = ( i * i for i in L)  #先赋值
>>> g
<generator object <genexpr> at 0x0000022979D4DA80>
>>> next(g) 
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
100
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

#可以看到每次使用next就会输出循环后续的结果,直至循环完成,但是这样一个一个敲太麻烦了,而生成器也是可迭代的数据,所以我们可以使用for循环
>>> g = ( i * i for i in L)
>>> for x in g:
...     print(x) 
... 
0
1
4
9
16
25
36
49
64
81
100
  • 从上面的例子可以看出,生成器是可以直接使用for循环调用的,所以说在实际使用生成器时,几乎不会使用next去依次调用
  • 下面引用一个案例,实现斐波拉契数列
# -*- coding: utf-8 -*-
def fbl(n):
    x,y,i = 0,0,1
    while x < n:
        print(i)
        y,i = i,y + i
        x = x + 1
    return 'done'

fbl(6)

#运行:
1
1
2
3
5
8

#解析
定义x为循环的次数,每次循环会加一,当x等于函数传入的参数n时,while循环就会结束
而y和i在每次循环时,y会赋予i的值,而i会赋予y+i的值,这样实现的效果就是:
1:y=1,x=0+1=1
2:y=1,x=1+1=2
3:y=2,x=1+2=3
4:y=3,x=2+3=5
5:y=5,x=3+5=8
更好理解的就是x2=y1+x1,x3=y2+x2,x4=y3+y3这种规律
  • 从上面的案例中可以看出,斐波拉契数列就是根据上一个运算结果推算出下一个运算结果,这就比较像生成器的特性了
  • 而上面定义的函数只需要把print(i)改为yield i就可以变成一个生成器:
# -*- coding: utf-8 -*-
def fbl(n):
    x,y,i = 0,0,1
    while x < n:
        yield i 
        y,i = i,y + i
        x = x + 1
    return 'done'

f = fbl(6)
print(f)
for a in f:
    print(a)
    
#运行:
<generator object fbl at 0x000001F1B9BED8C0>
1
1
2
3
5
8

#解析:
这里的函数和上面的普通函数只改变了一个关键字,但是因为这个关键字,使函数执行的流程发生了改变,上面的普通函数就是依次的顺序执行,遇到return语句或是到了最后一行语句就会返回,而这里的函数变成了只有在遇到next函数或for循环时才会在yield关键字的语句位置进行返回,再次使用next或继续for循环时,会从上次yield语句的位置继续执行,直到再次遇到yield语句然后再次进行返回,这里的函数其实就变成了生成器函数

#如果这里的解析比较难理解的话,可以看一下这个简单的示例:
# -*- coding: utf-8 -*-
def test():
    print('aaa')
    yield 
    print('bbb')
    yield
    print('ccc')
    yield

a = test()
next(a)
print("1")
next(a)
print("2")
next(a)
print("3")
next(a)

#运行:
aaa
1
bbb
2
ccc
3
Traceback (most recent call last):
  File "c:\Users\12488\Desktop\python\pachong.py", line 17, in <module>
    next(a)
StopIteration
这里其实就更直观了,在第一次调用时,在第一个yield停下了,从而输出了aaa,第二次从第一个yield位置继续执行在第二个yield的位置停下,从而输出的bbb,第三次从第二个yield的位置继续执行,在第三个的yield位置停下,从而输出了ccc,第四次的时候,因为已经没有yield关键字了,所以就报错了

注意:

1、如果一个函数中包含yield关键字,那么这个函数就会变成生成器函数,而调用一个生成器函数将会返回一个生成器的数据

2、调用生成器函数会创建一个生成器对象,多次调用生成器函数会创建多个相互独立的生成器,示例:

#修改一下脚本
# -*- coding: utf-8 -*-
def test():
    print('aaa')
    yield 
    print('bbb')
    yield
    print('ccc')
    yield

next(test())
print("1")
next(test())
print("2")
next(test())
print("3")
next(test())

#运行:
aaa
1
aaa
2
aaa
3
aaa
可以发现每次都是只到第一个yield就停下了,这就是因为只调用了生成器函数,所以每次都是创建新的生成器,而上一个脚本是把生成器函数赋值了,每次调用的是相同的生成器,很明显上一个脚本的写法才是正确的
  • 这里引用廖雪峰大神的一个案例:
1、在使用for循环调用生成器时,会发现拿不到生成器return语句的返回值,如果想拿到返回值,必须捕获StopIteration的错误,返回值包含在StopIteration的value值中:
# -*- coding: utf-8 -*-
def fbl(n):
    x,y,i = 0,0,1
    while x < n:
        yield i 
        y,i = i,y + i
        x = x + 1
    return 'done'

f = fbl(6)
while True:
    try:
        x = next(f)
        print('f:',x)
    except StopIteration as e:
        print('return value:',e.value)
        break
        
#运行:
f: 1
f: 1
f: 2
f: 3
f: 5
f: 8
return value: done

2、实现杨辉三角
# -*- coding: utf-8 -*-
def triangles():
    L = [1]
    while True:
        yield L
        X = [0] + L
        Y = L + [0]
        L = [X[i] + Y[i] for i in range(len(X))]

n = 0
results = []
for t in triangles():
    results.append(t)
    n = n + 1
    if n == 10:
        break

for t in results:
    print(t)

if results == [
    [1],
    [1, 1],
    [1, 2, 1],
    [1, 3, 3, 1],
    [1, 4, 6, 4, 1],
    [1, 5, 10, 10, 5, 1],
    [1, 6, 15, 20, 15, 6, 1],
    [1, 7, 21, 35, 35, 21, 7, 1],
    [1, 8, 28, 56, 70, 56, 28, 8, 1],
    [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
]:
    print('测试通过!')
else:
    print('测试失败!')       
    
#运行:
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
测试通过!


#解析:
def triangles():
    L = [1]
    while True:
        yield L
        x = [0] + L
        y = L + [0]
        L = [x[i] + y[i] for i in range(len(x))]
        
下面就是每一次循环时的规律,可以看出来每次都是相加、重组的一个流程  
L = [1]
x=[0,1],y=[1,0]
range(len(x)) = range(2)
x[0] + y[0] = 0 + 1 = 1
x[1] + y[1] = 1 + 0 = 1
[1,1]


L = [1,1]
x=[0] + [1,1] = [0,1,1]
y=[1,1] + [0] = [1,1,0]
range(len(x)) = range(3)
x[0] + y[0] = 0 + 1 = 1
x[1] + y[1] = 1 + 1 = 2
x[2] + y[2] = 1 + 0 = 1
[1,2,1]

L = [1,2,1]
x=[0] + [1,2,1] = [0,1,2,1]
y=[1,2,1] + [0] = [1,2,1,0]
range(len(x)) = range(4)
x[0] + y[0] = 0 + 1 = 1
x[1] + y[1] = 1 + 2 = 3
x[2] + y[2] = 2 + 1 = 3
x[3] + y[3] = 1 + 0 = 1
[1,3,3,1]

L = [1,3,3,1]
x=[0] + [1,3,3,1] = [0,1,3,3,1]
y=[1,3,3,1] + [0] = [1,3,3,1,0]
range(len(x)) = range(5)
x[0] + y[0] = 0 + 1 = 1
x[1] + y[1] = 1 + 3 = 4
x[2] + y[2] = 3 + 3 = 6
x[3] + y[3] = 3 + 1 = 4
x[4] + y[4] = 1 + 0 = 1
[1,4,6,4,1]

注意:生成器函数的调用会直接返回一个生成器对象,而普通函数会直接返回调用结果

四、迭代器

  • 经过上面的学习,可以知道可以直接进行for循环的数据类型有:列表(list),元组(tuple)、字典(dict)、集合(set)、字符串(str)等,这些都是集合数据类型的,还有一个种是生成器(generator),包括了生成器和生成器函数(带yield关键字的函数)
  • for循环可以作用于上述所说的所有数据类型,而这些数据类型又称为可迭代数据类型(Iterable),利用isinstance()函数可以判断一个数据是否为可迭代的数据类型
>>> from collections.abc import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable) 
True
>>> isinstance('aaa', Iterable) 
True
>>> isinstance((i for i in range(10)), Iterable) 
True
>>> isinstance(100, Iterable)                    
False
#注意:int类型不是可迭代的数据类型
  • 我们知道生成器不但可以使用for循环,还可以使用next()函数不断调用直到抛出StopIteration错误,而这种可以被next()函数调用并不断返回下一个值的数据类型,也叫做迭代器(Iterator),同样的使用isinstance()函数可以判断是否为迭代器:
>>> from collections.abc import Iterator
>>> isinstance([], Iterator) 
False
>>> isinstance({}, Iterator) 
False
>>> isinstance('aaa', Iterator) 
False
>>> isinstance((i for i in range(10)), Iterator) 
True
#可以看到只有生成器是迭代器

注意:生成器为Iterable而迭代器为Iterator

  • 经过上面的案例,可以看出生成器既是可迭代数据类型,也是迭代器数据类型,但是为什么其他的可迭代数据不是迭代器数据类型呢?如列表、字典、字符串等

    这是因为python中的迭代器表示的是一个数据流,这个数据流是可以被next()函数不断调用并返回下一个值,直到没有数据时报StopIteration错误。

    这也说明了迭代器的计算是惰性的,只有在需要返回下一个数据时才会进行计算,而列表、字典、字符串这些数据在创建的时候,里面的元素就已经定义好了,在需要返回时并不会计算,而是直接返回。

    他们的区别还在于迭代器可以表示一个无限大的数据流,例如所有自然数,因为他的计算模式是惰性的,而像列表、字典、字符串这种的,很明显存储的元素是有限的,所以它们不是迭代器的数据类型

  • 列表、字典、字符串等虽然不是迭代器的数据类型,但是可以通过函数iter()来获取一个迭代器的数据,例如:

>>> from collections.abc import Iterator
>>> isinstance(iter([]), Iterator) 
True
>>> isinstance(iter({}), Iterator) 
True
>>> isinstance(iter('aaa'), Iterator) 
True
  • 最后引入几个知识点:

1、python的for循环本质就是通过不断调用next()函数实现的

2、凡是for循环可以调用的类型都是可迭代数据类型

3、凡是可以使用next()函数不断调用输出结果的数据都是迭代器数据类型
以看出生成器既是可迭代数据类型,也是迭代器数据类型,但是为什么其他的可迭代数据不是迭代器数据类型呢?如列表、字典、字符串等

这是因为python中的迭代器表示的是一个数据流,这个数据流是可以被next()函数不断调用并返回下一个值,直到没有数据时报StopIteration错误。

这也说明了迭代器的计算是惰性的,只有在需要返回下一个数据时才会进行计算,而列表、字典、字符串这些数据在创建的时候,里面的元素就已经定义好了,在需要返回时并不会计算,而是直接返回。

他们的区别还在于迭代器可以表示一个无限大的数据流,例如所有自然数,因为他的计算模式是惰性的,而像列表、字典、字符串这种的,很明显存储的元素是有限的,所以它们不是迭代器的数据类型

  • 列表、字典、字符串等虽然不是迭代器的数据类型,但是可以通过函数iter()来获取一个迭代器的数据,例如:
>>> from collections.abc import Iterator
>>> isinstance(iter([]), Iterator) 
True
>>> isinstance(iter({}), Iterator) 
True
>>> isinstance(iter('aaa'), Iterator) 
True
  • 最后引入几个知识点:

1、python的for循环本质就是通过不断调用next()函数实现的

2、凡是for循环可以调用的类型都是可迭代数据类型

3、凡是可以使用next()函数不断调用输出结果的数据都是迭代器数据类型

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值