首页 > 编程语言 >浅谈python容器、迭代器与生成器

浅谈python容器、迭代器与生成器

时间:2023-02-02 20:55:51浏览次数:59  
标签:__ 容器 浅谈 迭代 python 生成器 iter next

前言:


for...in...循环时,与while不同的是,for可以自动访问容器中的下一个元素,这是为什么呢?

#用while循环访问列表容器
iter_a = iter(a)
while True:
  try:
    print(next(iter_a))
  except StopIteration:
    break
#用for循环访问列表容器
a = [1, 2, 3]
for i in a:
  print(i)

借助迭代器之后while就等效于for了,这也是for循环的底层实现逻辑


一、容器


通俗易懂地来说:容器就是用来储存数据指针的一个对象,方便使用者对一大堆的数据进行处理而不用去在乎它们究竟储存在内存的何处
在python中,容器有:元组、集合、字典、列表等


二、迭代器


前言中提到,python中for的奇妙之处在于借助了迭代器使得可以逐一遍历容器中的元素,那么迭代器究竟是什么呢?
在c语言中,要想访问容器中的下一个元素,就得借助指向下一个元素地址的指针,而迭代器正是用于完成这项任务的对象

迭代器:是指支持迭代容器的对象

class Classmate(object):
    """定义一个同学类"""
 
    def __init__(self):
        self.name = list()
        self.name_num = 0
 
    def add(self,name):
        self.name.append(name)
    
    def __iter__(self):
        return self   # 返回本身
 
    def __next__(self):
        if self.name_num < len(self.name):
           ret = self.name[self.name_num]
           self.name_num += 1
           return ret
 
        # 抛出异常,当循环后自动结束
        else:
              raise StopIteration

class1 =  Classmate()
class1.add("张三")
class1.add("李四")
class1.add("王五")

for name in class1:
    print(name)
#<<<张三
#<<<李四
#<<<王五

代码案例来源于Python 迭代器(Iterator)
上述为自定义一个迭代器的例子
迭代器必须具备__iter__:返回一个迭代器,本身是迭代器可返回本身
要想达到访问下一个元素的效果得有__next__:返回容器当前值,为访问下一个值做准备

我们再回到for循环中
在使用for循环时,首先先调用迭代器,使之返回一个可迭代对象


来源于python文档迭代器类型

step1:如果for循环遍历的是容器,便调用容器中的函数container.iter(),不难看出,容器对象中也有__iter__函数,所以容器也是迭代器,但是没有__next()函数,无法进行元素的遍历,所以这个函数会返回一个可迭代的对象,这个可迭代的对象中包含了__next,所以可以进行遍历。

step2:调用了__iter__()之后,需要调用iterator.next()返回值,并指向下一个元素,如上例所述。直到迭代器中所有的元素都访问完毕,抛出StopIteration结束。

  • for遍历容器与遍历非容器迭代器的不同

a = [1, 2, 3]
for i in a:
  print(i)

iter_a = iter(a)
while True:
  try:
    print(next(iter_a))
  except StopIteration:
    break

还是之前那个例子当用while去遍历后
当我再next(iter_a)发现报错,但是for可以反复遍历那个容器,而迭代器却只能遍历一次元素

---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_26288\3255143482.py in <module>
----> 1 next(iter_a)

StopIteration: 

这是因为容器中的container.iter()返回的是一个迭代器,每次访问都会创建一个迭代器对象,所以可以用for反复遍历,而当我们用while遍历迭代器时,迭代器只创建了一个,当我们第二次再访问相同的迭代器时就会报错
这也基于迭代器的性质

  • 迭代器的性质:

1.可以遍历。
2.打印迭代器无法查看其中的元素,也无法统计迭代器中元素个数(不能使用len())
3.想要获取迭代器中的元素,只能一个一个取。
4.这个元素被取出,迭代器中就再也没有这个元素。

  • iter()与next()函数

iter()可以将一个容器生成为一个迭代器,此时再放入for中只能遍历一次元素,next()用于遍历迭代器,返回当前元素,指向下一个元素

iter1 = iter('hello')
print(iter1)
print(next(iter1))
print(next(iter1))
print(next(iter1))

hello是一个字符串容器
输出:
<str_iterator object at 0x000001A81D239E50>
h
e
l

三、生成器

在迭代器的基础上有了生成器,可以说生成器是一个特殊的迭代器,节省了内存,通过使用调用函数体不断生成元素然后返回
在此之前,需要讲到yield,在我的理解中,yield相当迭代器的封装,这也是为什么说生成器是基于迭代器的原因吧
yield与return相似,对于普通函数,按顺序执行时遇到 return 或最后一行函数语句就会返回;但是yield不会在引用函数时就返回值,而是返回一个生成器对象,对于有 yield的生成器函数,每次调用 next() 方法遇到 yield 语句才返回,如果再次调用 next() 方法,那么就会从上次返回的 yield 语句位置继续执行。

这也正是它节省内存的原因,它不会最开始时就将所有元素生成,而是当你需要时再一个一个生成,通过next()调用元素

def intNum():
    print("开始执行")
    for i in range(5):
        yield i
num = intNum()
#调用 next() 内置函数
print(next(num))
#调用 __next__() 方法
print(num.__next__())
#通过for循环遍历生成器
for i in num:
    print(i)

运行结果:
开始执行
0
1
2
3
4
注意:生成器与迭代器拥有一样的性质,访问过的元素不能再次访问,所以当用for遍历时并没有输出0,1而是直接输出2,3,4

  • 生成器的创建方法:

1、生成器表达式
生成器表达式和列表推导式差不多,我们只需要把列表推导式的[]改为(),这样就是一个生成器表达式了。需要注意的是,列表推导式返回的是一个列表对象,而生成器表达式返回的是一个生成器对象,因此我们可以通过生成器表达式来创建一个生成器。

b = (i for i in range(5))

2、生成器函数
与普通函数不同的是,生成器函数不用return返回值而是用yield返回值

def example(n)
    for i in range(n):
      yield i

四、总结

  • 容器:数据指针的集合
  • 迭代器:用于更好的遍历容器,配合for使用
  • 生成器:基于迭代器的基础上,节省储存空间,何时用何时生成元素,关键词yield
  • 迭代器与生成器重要性质:元素只能访问一遍,都各有两种生成方法,一是函数生成法,而是创建迭代器对象或者生成器函数
  • 关键函数或关键词:iter,next,iter(),next(),yield

此随笔为学习迭代器与生成器之后做的总结与反思

标签:__,容器,浅谈,迭代,python,生成器,iter,next
From: https://www.cnblogs.com/KeepEarlyHours/p/17087385.html

相关文章