Python基础 G-01 列表生成式&生成器&迭代器

列表生成式&生成器&迭代器

一、列表生成式

Python内置的一种极其强大的生成列表 list 的表达式。返回结果必须是列表。

1.1、基本语法

[ 变量表达式 for 变量 in 表达式 ]

1.2、示例

a = [x ** 2 for x in range(1, 10)]
b = [x * x for x in range(1, 11) if x % 2 == 0]
c = [m + n for m in 'ABC' for n in '123']
d = {'Java': "99", 'C': "99", 'C++': "99"}
L = [k + '=' + v for k, v in d.items()]
print(a)
print(b)
print(c)
print(L)

1.3、说明

这样的写法就叫做列表生成式。通过列表生成式,可以直接创建一个列表。

二、生成器(generator)

2.1、背景

前面我们学习到了,通过列表生成式,我们可以直接创建一个列表。但是,受到内存的限制,列表容量是有限的,当列表元素很大的时候,会很浪费内存空间。(如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了)。为了解决这种问题,在Python中,提供了生成器(generator),生成列表的前几个元素,当需要用到后面的时候,在计算生成。从而节省内存空间。

2.2、定义

在Python中,这种一边循环一边计算后面元素的机制,称为生成器:generator。

2.3、使用

2.3.1、如何创建生成器
a、使用()类似列表生成式的生成器
使用方法

把列表生成式的中括号 [] 修改为圆括号即可 ()

代码示例
a = (x ** 2 for x in range(1, 10))
b = (x * x for x in range(1, 11) if x % 2 == 0)
c = (m + n for m in 'ABC' for n in '123')
d = {'Java': "99", 'C': "99", 'C++': "99"}
L = (k + '=' + v for k, v in d.items())
print(a)
print(b)
print(c)
print(L)

输出结果:

<generator object <genexpr> at 0x1052ec2b0>
<generator object <genexpr> at 0x1052ec468>
<generator object <genexpr> at 0x1052ec4c0>
<generator object <genexpr> at 0x1052ec518>
b、使用包含 yield 关键字的函数生成器
背景

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:1, 1, 2, 3, 5, 8, 13, 21, 34, … 这个就无法使用类似列表生成式定义。就要使用到函数生成器
实现100以内的斐波那契数代码:

def fib(max):
    a,b = 0,1
    n = 0  # 斐波那契数
    while n < max:
        n = a + b
        a = b # 把b的旧值给到a
        b = n # 新的b = a + b(旧b的值)
        print(n)
fib(100)
使用方法

在上述代码中,添加 yield 关键字,我们就可以将该函数变为函数生成器。

代码示例
def fib(max):
    a,b = 0,1
    n = 0  # 斐波那契数
    while n < max:
        n = a + b
        a = b # 把b的旧值给到a
        b = n # 新的b = a + b(旧b的值)
        #print(n)
        yield n # 程序走到这,就会暂停下来,返回n到函数外面,直到被next方法调用时唤醒
f = fib(100) # 注意这句调用时,函数并不会执行,只有下一次调用next时,函数才会真正执行
print(f)
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())

输出结果:

1
2
3
5
说明

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句暂停并返回数据到函数外,再次被next()调用时从上次返回的yield语句处继续执行。

2.3.2、如何访问生成器中的元素
a、使用 next 调用元素
作用:
  • next 方法会一个个的返回元素值,调用一次,返回一次下一个位置的元素。
  • 该方法在没有元素可以调用的时候,会返回 StopIteration 的错误
代码示例
>>> g = (x * x for x in range(10))
>>> 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)
Traceback (most recent call last):
  File "", line 1, in 
StopIteration
b、使用for循环遍历
作用
  • 上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代(遍历)对象
  • 通过for循环来迭代它,就不需要关心StopIteration的错误了。
代码示例
>>> g = (x * x for x in range(10))
>>> for n in g:
...     print(n)
...
0
1
4
9
16
25
36
49
64
81

三、迭代器

3.1、可迭代对象(Iterable)

3.1.1、什么是可迭代对象

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

  • 一类是集合数据类型,如list、tuple、dict、set、str等;
  • 一类是generator,包括生成器和带yield的generator function。
    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable,可迭代的意思就是可遍历、可循环。
3.1.2、如何判断可迭代对象

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

代码示例
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

3.2、迭代器(Iterator)

3.2.1、说明
  • 迭代是Python最强大的功能之一,是访问集合元素的一种方式。
  • 迭代器是一个可以记住遍历的位置的对象。
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
  • 迭代器有两个基本的方法:iter() 和 next()。
3.2.2、创建迭代器
a、创建普通迭代器

字符串,列表或元组对象都可用于创建迭代器:

>>> list=[1,2,3,4]
>>> it = iter(list)    # 创建迭代器对象
>>> print (next(it))   # 输出迭代器的下一个元素
1
>>> print (next(it))
2
>>>
b、创建类迭代器
说明

把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__()__next__()

  • __iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。
  • __next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。
    创建一个返回数字的迭代器,初始值为 1,逐步递增 1:
代码示例
class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    x = self.a
    self.a += 1
    return x
 
myclass = MyNumbers()
myiter = iter(myclass)
 
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))

输出结果:

1
2
3
4
5
补充

StopIteration异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
代码示例:

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    if self.a <= 20:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration
 
myclass = MyNumbers()
myiter = iter(myclass)
 
for x in myiter:
  print(x)
3.2.3、迭代器元素访问
使用 next() 函数
#!/usr/bin/python3
 
import sys         # 引入 sys 模块
 
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
 
while True:
    try:
        print (next(it))
    except StopIteration:
        sys.exit()
使用常规for语句进行遍历
#!/usr/bin/python3
 
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
for x in it:
    print (x, end=" ")
3.2.4、总结
  • 凡是可作用于for循环的对象都是Iterable类型;
  • 凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
  • 集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值