:
hasher = hashlib.sha256()
chunks = read_those_chunks()
map(hasher.update, chunks)
return hasher.hexdigest()
注意(whileループを使用して)、元calculate_checksums
からの明示的な反復が今map
の内部に隠されていること。基本的には、map
が繰り返しになりました。
read_those_chunks
がファイル全体を(おそらく)メモリに読み込むことを避けたいという障害があります。
def read_those_chunks(open_file, chunk_size):
offset = 0
while True:
yield open_file.readChunk(offset, chunk_size)
offset += chunk_size
以降のチャンク(またはEOFError
)で火災Deferred
Sを生成するジェネレータがあります:だから、最初のステップとして、その部分を実装します。残念ながら、map
でこれを使用することはできません。 、元の実装から反復を置き換えasync_map
以来
はmap
とmap
を交換しようとしているasync_map
はまだ確認してください、私たちからすべてのチャンクを訪問する責任です。だから今、地図を問わずこれに対処することができます実装繰り返し可能です。ただし、繰り返し(for
またはwhile
のいずれか)は、Deferred
とよく混合されません(混合するのは通常、inlineCallbacks
を取り出すときです)。したがってasync_map
は反復しません。それは繰り返します - 繰り返しの一般的な選択肢。各再帰呼び出しは、それ以上が存在しなくなるまで(または、EOFError
のためにこの場合に起こるように、Deferred
が失敗するまで)繰り返し可能性の次の要素で動作します。
再帰は関数と関数呼び出しで動作するため、Deferred
を使用した反復処理よりも優れています。 Deferred
は、関数と関数呼び出しを扱うことができます。関数をaddCallback
とDeferred
に渡すと、最終的にその関数が呼び出されます。反復は機能の小さな断片(「ブロック」または「スイート」と呼ばれることもあります)とDeferred
で処理できません。ブロックをaddCallback
に渡すことはできません。
は今Deferred
を作成するには、これらの2を使用している火災ダイジェストが計算されている場合:またasync_map
が、それは結果のリストを作成していないことにmap
異なることに気付くかもしれ
def calculate_checksum(open_file, chunk_size):
hasher = hashlib.sha256()
chunks = read_those_chunks(open_file, chunk_size)
d = async_map(hasher.update, chunks)
d.addErrback(lambda err: err.trap(EOFError))
d.addCallback(lambda ignored: hasher.hexdigest())
return d
それが作る関数呼び出しです。おそらくそれは、よりreduce
ようなものだ:
def async_reduce(function, iterable, lhs):
try:
d = next(iterable)
except StopIteration:
return lhs
d.addCallback(lambda rhs: function(lhs, rhs))
d.addCallback(lambda lhs: async_reduce(function, iterable, lhs))
return d
それはもちろん、まだ再帰の代わりに反復的です。
そしてhexdigestを計算するための還元関数は次のようである:
def update_hash(hasher, s):
hasher.update(s)
return hasher
それでcalculate_checksum
は次のようになる。
def calculate_checksum(open_file, chunk_size):
chunks = read_those_chunks(open_file, chunk_size)
d = async_reduce(update_hash, hashlib.sha256(), "")
d.addErrback(lambda err: err.trap(EOFError))
d.addCallback(lambda hasher: hasher.hexdigest())
return d
hasher
閉鎖を持っていないため、ビット進歩しています。
もちろん、inlineCallbacks
を避けるためにこの関数を書き換えることができる他にも多くの方法があります。私が選択した方法は、ジェネレータ関数の使用を排除するものではありません。したがって、あなたがエスケープしたいものなら、それは本当に助けにはなりません。そうであれば、ここで私がここで行ったように、問題を分解することができます。
リファクタリングまたはコードレビューのためにここをクリックしてください:https://codereview.stackexchange.com/ – Joe