Python高级特性-2

Python高级特性-2_第1张图片

列表生成式

#生成[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#直接创建
arr = list(range(0, 10))
print(arr)

#列表生成式
arr = [x for x in range(0, 10)]
print(arr)

上面两段代码效果相同,都是生成0~9的list,第二段代码使用的是列表生成式。

其中第二个x表示for..in迭代的元素,第一个x表示添加到list中的元素;第一个x还可以替换成其他的,例如表达式

arr = [0 for x in range(0, 10)]
print(arr)
#输出:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

arr = [x*2 for x in range(0, 10)]
print(arr)
#输出:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

for..in后面还能加上if条件判断。抱着怀疑的态度,试了试在直接使用for..in进行迭代的情况下添加if判断,结果报错了。

arr = [x * x for x in range(0, 10) if x % 2 == 0]
print(arr)
#输出:[0, 4, 16, 36, 64]

还有一个比较强大的地方,列表生成式支持for..in的叠加,也就是循环的嵌套

arr = [m + n for m in '123'for n in 'abc']
print(arr)
#输出:['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']

for..in所支持的迭代类型,在列表生成式中都是可以使用的,例如字符串,dirt,dirt.values(),dirt.items()等,都是可以使用的。而在列表生成式的第一个x的位置,出了表达式,还支持第二个x类型所支持的函数。

生成器(generator)

列表生成式是一次直接创建了一个完整的list,而生成器则不必创建一个完整的list,可以一边循环一边创建list中的元素,这样跟更加节省内存。

#生成式中的[]变成()
g = (x for x in range(10))

这样就创建了一个generator,并不是list,可以通过next(g)函数获取生成的元素,next会获取下一个生成的元素。而generator也是支持迭代的,这样才更加合理,不需要无限的调用next(g),并且不需要关心StopIteration的错误。当next(g)不能生成元素了会报StopIteration错误。

g = (x for x in range(10))
for n in g:
    print(n)

在较复杂的情况下,无法用迭代完成时,generator可以用函数来实现。比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

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

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'

上面的函数打印了斐波那契数列的前max个数,这里只需要把print(b)修改成yield(b)fib函数就变成了一个generator

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield(b)
        a, b = b, a + b
        n = n + 1
    return 'done'

直接打印fib(4)时,已经不是按照之前的规则输出数列,结束时输出done,而是这样一串字符


这是因为generator和函数的执行流程不同,函数是顺序执行遇到return或者执行完成就结束了;而generator则是在每次条用next时执行,遇到yield语句返回,再次执行next时从上次的yield继续执行。举个例子:

def odd():
    print('step 1')
    yield (1)
    print('step 2')
    yield (2)
    print('step 3')
    yield (3)


o = odd()
print(next(o))
print(next(o))
print(next(o))

输出结果:

step 1
1
step 2
2
step 3
3 

从输出结果可以看得出来,每调用一次next都会停在yield的地方,下一次执行next有会接着从这里开始。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next(o)就报错。

同时这里还会发现一个问题,当使用yield将函数变成generator函数是无法获取return的值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIterationvalue中。

迭代器

之前提高过迭代的概念,也就是for..in,支持的数据类型有listtupledictsetstr等;generatorgenerator函数也是支持的,这些都是Iterable对象。在迭代中有提到isinstance()函数可以判断一个对象是否是Iterable对象。

其中generator不仅可以使用for循环并且可以使用next()函数并不断返回下一个值,这样的对象被称为迭代器(Iterator)

同样可以使用isinstance()函数判断一个对象是否是Iterator对象

from collections import Iterator

print(isinstance([], Iterator))
print(isinstance({}, Iterator))
print(isinstance('', Iterator))

以上上种类型输出的结果都是False

这里有一点需要注意,generatorIterator,但listdictstr虽然是Iterable,却不是Iterator。使用iter()函数可以将listdictstrIterable变成Iterator

for循环的本质就是通过不断条用next()函数实现的。

你可能感兴趣的:(Python高级特性-2)