迭代器與生成器

@[toc]

1. 迭代器

我們以后不會自己去寫迭代器,只要學會使用迭代器就可以了。

1.1 迭代器的作用

如果有這樣的需求,展示列表中的所有數(shù)據(jù)。
實現(xiàn)方法:① while+索引+計數(shù)器;② 迭代器

<kbd>迭代器</kbd>:對可迭代對象(序列類型,如str/list/tuple/dict/set)中的元素進行逐一獲取。表象:具有next方法且每次調(diào)用都獲取可迭代對象中的元素(從前到后一個一個獲?。?/p>

1.2 迭代器的使用

① 列表轉(zhuǎn)換成迭代器方法一:<kbd>v = [1, 2, 3, 4, 5, 6]</kbd>,<kbd>val = iter(v)</kbd>(使用內(nèi)置函數(shù)iter)

# coding:utf-8
v = iter([1, 2, 3, 4, 5, 6])
print(v, type(v))
'''
<list_iterator object at 0x000001EF6A0E95F8> <class 'list_iterator'>
'''

② 列表轉(zhuǎn)換成迭代器方法二:<kbd>v = [1, 2, 3, 4, 5, 6]</kbd>,<kbd>val = v.__ iter__ ()</kbd>(使用__ iter__ 方法)

# coding:utf-8
v = [1, 2, 3, 4, 5, 6]
# val = iter(v)#內(nèi)部會調(diào)用__iter__方法
v2 = v.__iter__()
while True:
    val = v2.__next__()
    print(val)

③ 迭代器獲取每個值:反復調(diào)用<kbd>val.__ next __()</kbd>(val是迭代器對象)

# coding:utf-8
v = iter([1, 2, 3, 4, 5, 6])
val1 = v.__next__()
val2 = v.__next__()
val3 = v.__next__()
val4 = v.__next__()
val5 = v.__next__()
val6 = v.__next__()
print(val1, val2, val3, val4, val5, val6)
'''
1 2 3 4 5 6
'''
# coding:utf-8
v = iter([1, 2, 3, 4, 5, 6])
while True:
    try:
        val = v.__next__()
        print(val)
    except Exception as e:
        break

④ 直到報錯:StopIteration錯誤

# coding:utf-8
v = iter([1, 2, 3, 4, 5, 6])
while True:
    val = v.__next__()
    print(val)
'''
1
2
3
4
5
6
StopIteration
'''
1.3 for循環(huán)與迭代器

for循環(huán)的內(nèi)部使用的是迭代器:

# coding:utf-8
v = ['thanlon', 'kiku']
'''
1. for循環(huán)內(nèi)部會將v1轉(zhuǎn)換成迭代器
2. 內(nèi)部反復執(zhí)行“迭代器.__next__()”方法,一個個取值
3. 取完值不報錯
'''
for item in v:
    print(item)
'''
thanlon
kiku
'''
1.4 可迭代對象

① 可以被for循環(huán)且對象中具有iter()方法,還要返回一個迭代器(或生成器),

v = [1, 2, 3]
result = v.__iter__()  # 有__iter__方法,且返回迭代器對象(result),所以v是迭代器對象
print(result)  # result = <list_iterator object at 0x000001E11CB795C0>

② 可以被for循環(huán)

1.5 可迭代對象與迭代器之間關(guān)系

可迭代對象可以轉(zhuǎn)換成迭代器。

2. 生成器
2.1 生成器函數(shù)

① 函數(shù):

def func():
    return 'thanlon'
func()

② 生成器函數(shù)
如何判斷是生成器函數(shù):內(nèi)部是否包含yield

# 生成器函數(shù)(內(nèi)部是否包含yield)
def func():
    print('f1')
    yield 1
    print('f2')
    print('f2')
    yield 2
    print('f3')
    print('f3')
    print('f3')
    yield 3
    print('f4')
    print('f4')
    print('f4')
    print('f4')
    print('f4')
    
# 函數(shù)內(nèi)部代碼不會被執(zhí)行,返回一個生成器對象
v = func()
print(v, type(v))
'''
<generator object func at 0x0000021BC91F5570> <class 'generator'>
'''

生成器是可以被for循環(huán)的,一旦開始循環(huán)內(nèi)部代碼就會開始執(zhí)行:

# 生成器函數(shù)(內(nèi)部是否包含yield)
def func():
    print('f1')
    yield 1
    print('f2')
    print('f2')
    yield 2
    print('f3')
    print('f3')
    print('f3')
    yield 3
    print('f4')
    print('f4')
    print('f4')
    print('f4')
    print('f4')

v = func()
for item in v:
    print(item)
'''
f1
1
f2
f2
2
f3
f3
f3
3
f4
f4
f4
f4
f4
'''
2.2 yield from

從當前生成器跳到另一個生成器。

# coding:utf-8
def func():
    yield 3
    yield 4

def func2():
    yield 1
    yield 2
    yield from func()
    yield 5

result = func2()
for item in result:
    print(item)
# coding:utf-8
def func():
    return 3

def func2():
    yield 1
    yield 2
    yield from func()
    yield 5

result = func2()
for item in result:
    print(item)
'''
TypeError: 'int' object is not iterable
'''
# coding:utf-8
# 使用可迭代的列表類型
def func():
    return [3, 4]

def func2():
    yield 1
    yield 2
    yield func()
    yield 5

result = func2()
for item in result:
    print(item)
'''
1
2
[3, 4]
5
'''
# coding:utf-8
def func():
    return [3, 4]

def func2():
    yield 1
    yield 2
    # yield func()  # 把[3, 4]當作整體拿過來
    yield from func()  # 把[3,4]拆開拿過來
    yield 5

result = func2()
for item in result:
    print(item)
'''
1
2
3
4
5
'''
2.3 生成器例子
# coding:utf-8
def func():
    return 1
    if 1 != 1:
        yield 2
        yield 3

v = func()
print(v, type(v))
'''
<generator object func at 0x000001D3974F5570> <class 'generator'>
'''
# coding:utf-8
def func():
    while True:
        yield 1

val = func()
print(val)  # <generator object func at 0x000002CC842C5570>
for item in val:
    print(item)
# coding:utf-8
def func():
    count = 1
    while True:
        yield count
        count += 1

val = func()
print(val)
for item in val:
    print(item)
# coding:utf-8
def func():
    return 1
    yield 2
    yield 3

val = func()
for item in val:
    print(item)  # 由于return的作用,無內(nèi)容
# coding:utf-8
def func():
    yield 2
    return 111
    yield 3

val = func()
for item in val:
    print(item)
'''
2
'''
# coding:utf-8
def func():
    count = 1
    while True:
        yield count
        count += 1
        if count == 101:
            return
           
val = func()
for item in val:
    print(item)
'''
打印1~100
'''
2.4 生成器總結(jié)

函數(shù)中如果存在yield(注意與return無關(guān)),那么這個函數(shù)就是一個生成器函數(shù)。調(diào)用一個生成器函數(shù)會返回一個生成器對象,生成器只有被for循環(huán)時,生成器函數(shù)內(nèi)部的代碼才會被執(zhí)行,生成器每次循環(huán)都會獲取yield返回的值。

2.5 生成器應用示例

① 讀取文件案例:分批讀取文件,將文件的內(nèi)容返回給調(diào)用者

# coding:utf-8
def func():
    cursor = 0
    while True:
        f = open('log.txt', 'r', encoding='utf-8')
        f.seek(cursor)
        data_list = []
        for i in range(5):  # 每次讀5條
            line = f.readline()
            if not line:
                return
            data_list.append(line)
        cursor = f.tell()  # 獲取當前游標位置
        f.close()
        for row in data_list:
            yield row

for item in func():
    print(item)

② redis源碼示例:
安裝第三方模塊Redis:<kbd>pip install redis</kbd>

import redis

conn = redis.Redis(host='……')
# scan_iter()是一個生成器函數(shù)
conn.scan_iter()
def scan_iter(self, match=None, count=None):
    """
    Make an iterator using the SCAN command so that the client doesn't
    need to remember the cursor position.

    ``match`` allows for filtering the keys by pattern

    ``count`` allows for hint the minimum number of returns
    """
    cursor = '0'
    while cursor != 0:
        # 每次取100條數(shù)據(jù)
        # cursor:取完之后的游標位置
        # data:本次取出來的100條數(shù)據(jù)
        cursor, data = self.scan(cursor=cursor, match=match, count=count)
        for item in data:
            yield item
2.6 生成器補充

① 生成器的兩個作用:

  • 生成數(shù)據(jù)
  • 迭代

② 生成器是特殊的迭代器
生成器有next方法:

# coding:utf-8
def func():
    yield 1
    yield 2
    yield 3

v = func()  # v是生成器(對象)
# print(v, type(v))  # <generator object func at 0x0000023986405570> <class 'generator'>
# print(dir(v))  # 查看生成器v中都有哪些方法,dir(v)返回列表
for i in dir(v):
    print(i)
'''
__class__
__del__
__delattr__
__dir__
__doc__
__eq__
__format__
__ge__
__getattribute__
__gt__
__hash__
__init__
__init_subclass__
__iter__
__le__
__lt__
__name__
__ne__
__new__
__next__
__qualname__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
close
gi_code
gi_frame
gi_running
gi_yieldfrom
send
throw
'''

且每次調(diào)用都獲取生成器對象中的元素:

# coding:utf-8
def func():
    yield 1
    yield 2
    yield 3

v = func()  # v是生成器(對象),也是特殊的迭代器對象
result = v.__next__()
print(result)
result = v.__next__()
print(result)
result = v.__next__()
print(result)
'''
1
2
3
'''

③ 生成器是特殊的可迭代對象:生成器中有iter方法

# coding:utf-8
'''
把v當做可迭代對象
'''
def func():
    yield 1
    yield 2
    yield 3

v = func()
result = v.__iter__()
print(result)
'''<generator object func at 0x00000237F7135570>'''

如果一個對象有iter()方法且返回一個迭代器稱這個對象是可迭代對象。如果一個對象,它有iter()方法,它返回一個生成器,它也是可迭代對象。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容