Python詳細解析之容器、可迭代物件、迭代器以及生成器

WBOY
發布: 2022-04-08 20:31:09
轉載
1764 人瀏覽過

這篇文章為大家帶來了關於python的相關知識,其中主要介紹了關於容器、可迭代對象、迭代器以及生成器的相關問題,下面就一起來看一下,希望對大家有幫助。

Python詳細解析之容器、可迭代物件、迭代器以及生成器

推薦學習:python影片教學

在剛開始學Python的時候,是不是常常會聽到大佬們在講容器、可迭代物件、迭代器、生成器、列表/集合/字典推導式等等眾多概念,其實這不是大佬們沒事就擱那扯專業術語來裝B,而是這些東西都得要明白的,光知道字串、列表等基礎還是不夠的,尤其是在Python的資料結構方面。

今天就來跟大家講Python中的容器、可迭代物件、迭代器和生成器這些難理解的概念,讓你的Python基礎更上一層樓!

一、容器

1.什麼是容器?

在Python中,容器是把多種元素組織在一起的資料結構,容器中的元素就可以逐一迭代取得。說穿了,它的作用就像它的名字一樣:用來存放東西(數據)。

容器其實是不存在的,它並不是一種資料類型,只是人為的一種概念,只是為了方便學習所創造的一個概念詞,它可以用成員關係運算子(in或not in)來判斷物件是否在容器裡面。

當然了,它不是我創造的,我沒有那麼大本事哈,是官方創造的好吧,你也不用擔心我是在教你一些奇奇怪怪的名詞,說出去別人都聽不懂…python中都是這麼叫的。 常見的容器類型有列表(list)、元組(tuple)、字串(str)、字典(dict)以及集合(set )

既然容器裡面的資料是可以迭代取得的,那麼我們又得來學一個新概念:可迭代物件。


二、可迭代物件

1.什麼是可迭代物件?

在python中,可迭代物件並不是指某種特定的資料類型,它是指儲存了元素的一個容器物件

也就是說,如果容器裡面沒有儲存數據,那它就不是可迭代對象,並不是所有的容器都是可迭代對象,容器包含但並不僅限於可迭代對象。

注意兩個點:

1.很多容器都是可迭代对象(容器包含了可迭代对象)。

2.一个可迭代对象是不能独立的进行迭代的,迭代是通过for来完成的,凡是可迭代对象都可以直接使用for循环进行访问。
登入後複製

for迴圈大家應該不陌生吧?有沒有想過,for迴圈內部是怎麼實現的?比如說這個for迴圈的例子,為什麼能輸出列表裡的每一個元素?它的內部是怎麼實現的?

Python詳細解析之容器、可迭代物件、迭代器以及生成器

其實for迴圈做了兩件事:

1.使用 __iter__() 返回1个迭代器,迭代器在下面会讲,这里先知道有这么个东西。

2.使用 __next__() 获取迭代器中的每一个元素。
登入後複製

那麼我們不用for迴圈來輸出清單裡的每一個元素,

l = [1,2,3,4]# for i in l:#     print(i)ite =l.__iter__() #接收一下ietr()干了什么print(ite)  
#打印print(ite.__next__())    
#for循环干第2件事情的时候做的第1步print(ite.__next__())    
#for循环干第2件事情的时候做的第2步print(ite.__next__())   
 #for循环干第2件事情的时候做的第3步print(ite.__next__())    
#for循环干第2件事情的时候做的第4步
登入後複製

輸出結果:

Python詳細解析之容器、可迭代物件、迭代器以及生成器

可以看出來,如果我們去掉哪行列印ite的程式碼,執行效果就是跟for迴圈輸出清單裡面的每一個元素是一樣的,for迴圈裡面限定了範圍是4次,實際上就執行了1次__iter__()和4次__next__(),也就是說for迴圈存取迭代物件的本質就是透過這樣去實現的。

而且,for迴圈本質上乾的那兩件事情,缺一不可,也就是說如果沒有__iter__()先回傳了迭代器,__next()__也無法取得到元素,恰恰說明了前面說要注意的兩點中的第2點:一個可迭代物件是不能獨立的進行迭代的。

有兩個內建函數跟它們原理是一樣的,本質相同,一般要用的話用內建函數要方便一些,起碼不用寫那麼多下劃線:

内置函数 iter() 的本质是 __inter__() ,也是返回一个迭代器。

内置函数 next() 的本质是 __next__(),也是有了迭代器之后获取元素。
登入後複製

Python詳細解析之容器、可迭代物件、迭代器以及生成器

可以看出來結果也是一模一樣的,既然講到了迭代器,那就來看看什麼是迭代器。

三、迭代器

透過上面的for循環例子我們大概也能看得出來,

只要是实现了__iter__()和__next__()的对象,就是迭代器,迭代器是一个可迭代对象。

总之,迭代器是有__iter__()生成,可以通过__next__()进行调用。
登入後複製

既然如此,我們在學Python基礎的時候講過range( )是一個可迭代對象,那麼它也是可以透過__iter__()產生一個迭代器的。

Python詳細解析之容器、可迭代物件、迭代器以及生成器


四、序列

序列在【賦值語句】那個專題文章中我有提過,這裡再講一下,序列也是一個抽象的概念,它包含了列表、元組和字串,它本身是不存在的,也是便於學習所創造的概念詞。

可迭代对象包含序列,既然序列包含了列表、元组和字符串,前面我们的例子中也涉及到 了,所以说序列可以被iter()和next()使用

序列可以分为有限序列和无限序列。有限序列就是有范围的,比如说range(10)就已经限定了范围,相反的,无限序列也就是没有限定范围的序列。

我们来生成一个无限序列,这里需要用到1个新模块itertools,itertools用于高效循环的迭代函数集合,它下面有一个方法count(),可生成迭代器且无范围,可以理解为无限迭代器。

Python詳細解析之容器、可迭代物件、迭代器以及生成器

通过这个例子我们可以看出来,只要执行一次,next()就会获取一次迭代器里面的内容并逐次获取,我这里只写了4个next(),你多写几次就会多输出几次。

像next()这种什么时候需要就什么时候调用的机制叫做懒加载机制,也叫懒汉式加载;

相反地就有饿汉式加载。比如for循环这种的,只要一执行就会把可迭代器里面的所有对象都获取。


五、列表推导式

列表推导式跟生成器有关,在讲生成器之前,需要先知道什么是列表推导式,列表推导式就是生成列表的一种方法,语法是这样的:

l = [i for i in 可迭代对象]
登入後複製

i表示要放进列表里的对象,for循环是一个式子。

比如我们用列表推导式来生成一个列表试试:

l = [i for i in range(5)]print(l)
登入後複製

运行结果:

[0, 1, 2, 3, 4]
登入後複製

运用列表推导式可以很方便地生成我们想要的列表。

同时它也有很多灵活的用法,比如在后面加上条件判断

l = [i for i in range(5) if 4<p>运行结果:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">[0, 1, 2, 3, 4]
登入後複製

if后面的条件判断为真,则可以正常生成列表,如果为假,则列表推导式是无效的,此时的l将是一个空列表。

还有其他灵活的用法,比如操作前面的i,比如让i的数值全都翻2倍:

Python詳細解析之容器、可迭代物件、迭代器以及生成器

我们把迭代对象换一下,换成字符串,也同样可以输出,只是*在字符串里面表示重复操作符,所以效果变成了这样:

Python詳細解析之容器、可迭代物件、迭代器以及生成器

不仅如此,前面的i*2我们还可以用函数来进行操作,比如:

Python詳細解析之容器、可迭代物件、迭代器以及生成器

总而言之,列表推导式就是用来快速和自定义生成列表的一种方法,很灵活

那么有人可能会举一反三了,列表推导式都是用 [] 来进行操作的,那如果用()来操作行吗?它会不会生成一个元组?我们来看看:

Python詳細解析之容器、可迭代物件、迭代器以及生成器

[] 换成()之后,返回的是一个生成器generrator ,那么下面我们再来讲讲生成器:


六、生成器

生成器是真实存在于Python中的对象,与容器这种概念词是不同的,它是可以直接通过next()进行调用的。

1.生成器的第一种创建方法:生成器表达式

第一种创建方法跟列表推导式是差不多的,就是 [] 换成了():

l = (i for i in 可迭代对象)
登入後複製

比如我们来生成一个生成器,看看能不能用next()直接调用:

l = (i for i in "abcd")print(next(l))
登入後複製

运行结果:

a
登入後複製

可以看出,生成器是可以直接调用的。那么既然生成器可以被next()调用,那么生成器就是一个特殊的迭代器,是一个可迭代对象

2.生成器的第二种创建方法:yield

除了用上面那种方法创建生成器,还可以用yield来创建,方法如下:

yield 关键字
登入後複製

比如说我们用一个函数中包含yield来创建生成器:

def fun():
    a = 10
    while 1:
        a += 1
        yield a


b = fun()print(b)
登入後複製

运行结果:

<generator></generator>
登入後複製

结果就是生成了一个生成器,而且此时的函数fun()就已经不再是一个函数了,它是一个生成器,只要函数中出现了yield,函数就变成了生成器。

为什么while循环没有一直执行?先不着急,我们输出看看:

def fun():
    a = 10
    while 1:
        a += 1
        yield a


b = fun()print(next(b))print(next(b))print(next(b))
登入後複製

运行结果:

111213
登入後複製

我调用了三次,所以它就运行了三次,while循环虽然存在,但是却不起作用,是因为前面我们提过的懒汉式加载

什么时候需要了,什么时候用next()调用,就是懒汉式加载,不像饿汉式加载那样,提前生成了所有对象,如果这里换成for循环来完成,比如:

def fun():
    a = 10
    while 1:
        a += 1
        print(a)b = fun()
登入後複製

运行之后程序将会进入死循环,一直给a自加1,你可以试试看效果,这就是饿汉式加载提前生成了迭代器并调用了全部迭代器对象,饿汉式加载占用资源的放大镜

七、小结

今天讲的内容可能听起来比较枯燥,这也是没得办法的,有些东西第一次听可能有点”难以下咽“,见得多了之后就习惯了,你得强迫自己去试着接受和理解这些抽象的东西。

最后用一张图来总结一下它们的关系:

Python詳細解析之容器、可迭代物件、迭代器以及生成器

推荐学习:python教程

以上是Python詳細解析之容器、可迭代物件、迭代器以及生成器的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:csdn.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門推薦
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!