Python経験-反復器とジェネレータ
9675 ワード
反復器反復器は、集合内の要素にアクセスする方法(不活性)であり、以下の標的のアクセス方法とは異なり、アクセスを返すことができない. 反復プロトコル: 反復可能オブジェクトは
IterableとIteratorがiterを呼び出すと、まず が反復値を返すのは、Iteratorタイプで カスタムタイプを巡回するには、その内部に
例:
ビルダー yieldキーワードが存在する限り、ジェネレータ関数であり、一般的な関数としてアクセスできない. ジェネレータオブジェクトはpythonがバイトコードをコンパイルするときに生成される. は、すべてのメモリをすぐに割り当てる必要がなく、アクセスするたびにyieldの値を返します.
例:
実装の詳細:
例:ジェネレータで大きなファイルを読み込む
ジェネレータ値
ジェネレータの起動: next:ジェネレータから値を取得します(他の関数呼び出しのために値を外部に送信します). send:ジェネレータにパラメータを転送したり、ジェネレータを再起動して次のyieldに実行したりして、yieldの値を返したりすることができます. ジェネレータがNone以外の値を起動、送信する前に、事前に起動する必要があります.
には、
yield from
yield fromとyieldの違い
yield fromは、呼び出し元とサブジェネレータの間に双方向チャネル(コパスで別のコパスを呼び出す)を確立することもできます.
実装の原理
まとめ:サブジェネレータが生産した値は、呼び出し元に直接伝達される.呼び出し元が サブジェネレータが終了すると、最後の 呼び出し時に は依頼生成器の異常に伝達され、 は、委任ジェネレータで呼び出すとする.close()または受信
__iter__
__next__
、IterableとIteratorに対応;__iter__
を実装するだけで、反復器を構築するには__next__
を実装する必要があります.from collections.abc import Iterable, Iterator
a = [1, 2] # list Iterable Iterator
iter_rator = iter(a)
print (isinstance(a, Iterable))
print (isinstance(iter_rator, Iterator))
IterableとIterator
__iter__
が実現されたかどうかを判断し、存在しない場合はデフォルトの反復器を作成し、__getitem__
を利用して遍歴する.__iter__
は、Iteratorタイプを返さなければならない.__next__
で実現され、またIterator内部でインデックス値を維持する必要がある(ロールバックアクセスは許可されない).__iter__
を定義し、戻る反復器オブジェクトを定義する必要があります(内部実装__next__
).例:
from collections.abc import Iterator
class Company(object):
def __init__(self, employee_list):
self.employee = employee_list
def __iter__(self):
return MyIterator(self.employee)
# def __getitem__(self, item):
# return self.employee[item]
class MyIterator(Iterator):
def __init__(self, employee_list):
self.iter_list = employee_list
self.index = 0
def __next__(self):
try:
word = self.iter_list[self.index]
except IndexError:
raise StopIteration
self.index += 1
return word
if __name__ == "__main__":
company = Company(["tom", "bob", "jane"])
my_itor = iter(company)
# while True:
# try:
# print (next(my_itor))
# except StopIteration:
# pass
# next(my_itor)
for item in company:
print (item)
ビルダー
例:
def fib(index):
if index <= 2:
return 1
else:
return fib(index-1) + fib(index-2)
def fib2(index):
re_list = []
n, a, b = 0, 0, 1
while n
実装の詳細:
# python
import inspect
frame = None
def foo():
bar()
def bar():
global frame
frame = inspect.currentframe()
#
"""
python.exe PyEval_EvalFramEx(c ) foo (stack frame)
foo bar (python , , ),
, 。
"""
import dis
print(dis.dis(foo))
foo()
print(frame.f_code.co_name) # bar
caller_frame = frame.f_back
print(caller_frame.f_code.co_name) # foo
def gen_func():
yield 1
name = "ywh"
yield 2
age = 30
return "aimei"
import dis
gen = gen_func() # PyGenObject frame (PyCodeObject + PyCodeObject)
print (dis.dis(gen))
print(gen.gi_frame.f_lasti) # ,
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
next(gen)
print(gen.gi_frame.f_lasti)
print(gen.gi_frame.f_locals)
class company:
def __getitem__(self, item):
pass
from collections import UserList # Python List( `__next__`,yield)
例:ジェネレータで大きなファイルを読み込む
# , ( f.read())
def myreadlines(f, newline):
buf = "" # ,
while True:
while newline in buf: # , buf
pos = buf.index(newline)
yield buf[:pos] #
buf = buf[pos + len(newline):]
chunk = f.read(4096) # 4096
if not chunk: #
yield buf
break
buf += chunk
with open("input.txt") as f:
for line in myreadlines(f, "{|}"):
print(line)
ジェネレータ値
ジェネレータの起動:
gen.send(None)
next(gen)
close
(次回yieldを実行すると異常が放出される)、throw
(実行関数が異常を自発的に放出する)の方法もあります.def gen_func():
html = yield "http://projectsedu.com" # gen.send(html) html
print(html) # send
return "ywh"
gen = gen_func()
# url = gen.send(None)
url = next(gen)
html = "ywh"
gen.send(html)
gen.stop() # ( yield)
gen.throw(Exception, 'message') #
yield from
chain
(連結処理反復可能オブジェクト)、yield from
およびyield
from itertools import chain
li = [1, 2, 3]
di = {
"ywh1": "1", "ywh2": "2"
}
for value in chain(li, di, range(5, 10)):
print(value)
def my_chain(*args, **kwargs):
for my_iterable in args:
yield from my_iterable # iterable , yield
# for value in my_iterable:
# yield value
yield fromとyieldの違い
def g1(iterable): # , yield range(10)
yield iterable
def g2(iterable): # range(10) , yield
yield from iterable
for value in g1(range(10)):
print(value)
for value in g2(range(10)):
print(value)
yield fromは、呼び出し元とサブジェネレータの間に双方向チャネル(コパスで別のコパスを呼び出す)を確立することもできます.
final_result = {}
def sales_sum(pro_name):
total = 0
nums = []
while True:
x = yield
print(pro_name+" : ", x)
if not x:
break
total += x
nums.append(x)
return total, nums
# ( )
def middle(key):
while True:
final_result[key] = yield from sales_sum(key)
print(key + " !!")
def main():
data_sets = {
"ywh ": [1200, 1500, 3000],
"ywh ": [28, 55, 98, 108],
"ywh ": [280, 560, 778, 70],
}
for key, data_set in data_sets.items():
print("start key:", key)
m = middle(key)
m.send(None) # middle
for value in data_set:
m.send(value) #
m.send(None)
print("final_result:", final_result)
if __name__ == '__main__':
main()
実装の原理
# pep380
# 1. RESULT = yield from EXPR
#
"""
_i: ,
_y:
_r:yield from
_s: send()
_e:
"""
_i = iter(EXPR) # EXPR ,_i ;
try:
_y = next(_i) # , _y ;
except StopIteration as _e:
_r = _e.value # `StopIteration` , `value` _r, ;
else:
while 1: # , ;
_s = yield _y # , `send()` , _s ;
try:
_y = _i.send(_s) # _s, ;
except StopIteration as _e:
_r = _e.value # , `value` _r, , ;
break
RESULT = _r # _r yield from 。
"""
1. , , .throw() .close() ;
2. .throw() .close() , , ;
3.
4. next() .send(None) , next() , .send() None , .send() ;
"""
_i = iter(EXPR)
try:
_y = next(_i)
except StopIteration as _e:
_r = _e.value
else:
while 1:
try:
_s = yield _y
except GeneratorExit as _e:
try:
_m = _i.close
except AttributeError:
pass
else:
_m()
raise _e
except BaseException as _e:
_x = sys.exc_info()
try:
_m = _i.throw
except AttributeError:
raise _e
else:
try:
_y = _m(*_x)
except StopIteration as _e:
_r = _e.value
break
else:
try:
if _s is None:
_y = next(_i)
else:
_y = _i.send(_s)
except StopIteration as _e:
_r = _e.value
break
RESULT = _r
まとめ:
send()
を介して送信した値は、サブジェネレータに直接伝達される.送信がNone
である場合、サブジェネレータの__next__()
メソッドが呼び出され、None
でない場合、サブジェネレータのsend()
メソッドが呼び出される.return EXPR
は、StopIteration(EXPR)
の異常をトリガーします.yield from
式の値は、サブジェネレータが終了したときにStopIteration
に渡される異常の最初のパラメータである.StopIteration
の異常が発生した場合、依頼ジェネレータは運転を再開し、他の異常は「泡が立つ」.GeneratorExit
を除いて、他のすべての異常がサブ生成器のthrow()
方法に伝達される.throw()
が呼び出されたときにStopIteration
の異常が発生した場合、依頼ジェネレータの運転を再開し、他の異常はすべて上向きに「泡が立つ」.GeneratorExit
異常は、サブジェネレータのclose()
メソッドを呼び出し、なければ呼び出さない.close()
が呼び出されたときに異常が放出されると、上向きに「泡が立つ」ようになり、そうでなければ依頼ジェネレータはGeneratorExit
異常を放出する.