[解決済み】Python 3.3の "yield from "構文の主な用途は何ですか?
質問
を理解するのに苦労しています。 PEP 380 .
-
という場面は?
yield from
は有効ですか? - 古典的な使用例とは?
- なぜマイクロスレッドと比較されるのですか?
これまで、私はジェネレータは使っていましたが、コルーチン( PEP-342 ). いくつかの類似点はありますが、ジェネレータとコルーチンは基本的に2つの異なる概念です。コルーチン(ジェネレータだけでなく)を理解することが、新しい構文を理解するための鍵となります。
IMHO コルーチンはPythonの機能の中で最も曖昧なものです。 ほとんどの本では、役に立たないし、面白くもないように書かれています。
素晴らしい回答をありがとうございました。 アグフ とリンクしているコメント デービッド・ビーズリー・プレゼンテーション .
解決するには?
まず、ひとつだけ整理しておきましょう。という説明は
yield from g
と同等です。
for v in g: yield v
というのは、正当に評価することすらできません。
何に対して
yield from
がすべてです。なぜなら、正直に言うと、もしすべての
yield from
を拡張するだけです。
for
ループを追加する必要はありません。
yield from
を言語に追加し、Python 2.xで実装される新機能の束を排除してしまうのです。
何
yield from
は、それは
呼び出し側と副生成側の間の透過的な双方向接続を確立する。
:
-
接続は、生成される要素だけでなく、すべても正しく伝搬するという意味で、"transparent" です(例えば、例外は伝搬されます)。
-
接続はquot;bidirectional(双方向)である。 から と へ ジェネレータです。
(
TCPの話なら。
yield from g
は、「私のクライアントのソケットを一時的に切断し、この他のサーバーのソケットに再接続してください。
)
ちなみに、もしあなたが ジェネレータへのデータ送信 を読む必要があります。 コルーチン はとても便利です。 サブルーチン ) が、残念ながらPythonではあまり知られていません。 Dave Beazleyのコルーチンに関する不思議な講座 は素晴らしい手始めです。 スライド24~33を読む をご覧ください。
ジェネレータからデータを読み出すには、yield from
def reader():
"""A generator that fakes a read from a file, socket, etc."""
for i in range(4):
yield '<< %s' % i
def reader_wrapper(g):
# Manually iterate over data produced by reader
for v in g:
yield v
wrap = reader_wrapper(reader())
for i in wrap:
print(i)
# Result
<< 0
<< 1
<< 2
<< 3
を手動で反復処理する代わりに
reader()
を使えばいいのです。
yield from
である。
def reader_wrapper(g):
yield from g
これでうまくいき、1行のコードを省くことができました。そしておそらく、意図が少し明確になったでしょう(そうでない場合もありますが)。しかし、人生を変えるようなことは何もありません。
yield fromを使ったジェネレータ(コルーチン)へのデータ送信 - Part 1
さて、もっと面白いことをやってみましょう。というコルーチンを作ってみましょう。
writer
これは送られてきたデータを受け取り、ソケットやfdなどに書き込むものです。
def writer():
"""A coroutine that writes data *sent* to it to fd, socket, etc."""
while True:
w = (yield)
print('>> ', w)
さて,問題は,ラッパー関数がライターへのデータ送信をどのように処理するかです.
透過的に
に送信されます。
writer()
?
def writer_wrapper(coro):
# TBD
pass
w = writer()
wrap = writer_wrapper(w)
wrap.send(None) # "prime" the coroutine
for i in range(4):
wrap.send(i)
# Expected result
>> 0
>> 1
>> 2
>> 3
ラッパーに必要なのは
受け入れる
を処理する必要があります。
StopIteration
のループを使い果たしたとき。明らかに、ただ
for x in coro: yield x
ではダメなんです。以下は、動作するバージョンです。
def writer_wrapper(coro):
coro.send(None) # prime the coro
while True:
try:
x = (yield) # Capture the value that's sent
coro.send(x) # and pass it to the writer
except StopIteration:
pass
あるいは、こうすることもできます。
def writer_wrapper(coro):
yield from coro
これで6行のコードが節約でき、ずっと読みやすくなり、そしてちゃんと動くようになりました。魔法のようです。
ジェネレータの生成元へデータを送る - その2 - 例外処理
もっと複雑にしてみましょう。ライターが例外を処理する必要がある場合はどうすればいいのでしょうか?例えば
writer
を処理します。
SpamException
と表示されます。
***
に遭遇した場合。
class SpamException(Exception):
pass
def writer():
while True:
try:
w = (yield)
except SpamException:
print('***')
else:
print('>> ', w)
このままでは
writer_wrapper
? 動作しますか?試してみましょう。
# writer_wrapper same as above
w = writer()
wrap = writer_wrapper(w)
wrap.send(None) # "prime" the coroutine
for i in [0, 1, 2, 'spam', 4]:
if i == 'spam':
wrap.throw(SpamException)
else:
wrap.send(i)
# Expected Result
>> 0
>> 1
>> 2
***
>> 4
# Actual Result
>> 0
>> 1
>> 2
Traceback (most recent call last):
... redacted ...
File ... in writer_wrapper
x = (yield)
__main__.SpamException
えーと、うまくいかないのは
x = (yield)
が例外を発生させるだけで、すべてが止まってしまいます。うまくいくようにしましょう。しかし、手作業で例外を処理し、それをサブジェネレータに送ったり投げたりして(
writer
)
def writer_wrapper(coro):
"""Works. Manually catches exceptions and throws them"""
coro.send(None) # prime the coro
while True:
try:
try:
x = (yield)
except Exception as e: # This catches the SpamException
coro.throw(e)
else:
coro.send(x)
except StopIteration:
pass
これは有効です。
# Result
>> 0
>> 1
>> 2
***
>> 4
でも、これもそうなんです!
def writer_wrapper(coro):
yield from coro
は
yield from
サブジェネレータに値を送ったり、値を投げたりすることを透過的に処理します。
しかし、これでもまだ、すべてのコーナーケースをカバーできているわけではありません。外側のジェネレーターが閉じている場合はどうなるのでしょうか?サブジェネレータが値を返す場合(そう、Python 3.3+では、ジェネレータは値を返すことができます)、戻り値はどのように伝搬されるべきでしょうか?
その
yield from
すべてのコーナーケースを透過的に処理するのは、実に印象的です。
.
yield from
は、魔法のように動作し、すべてのケースを処理します。
個人的には
yield from
は、キーワードの選択としては不適切です。
双方向
の性質が明らかになる。他にも提案されたキーワードがありました(例えば
delegate
しかし、新しいキーワードを追加することは、既存のキーワードを組み合わせることよりもはるかに困難であるため、却下された。
まとめると、以下のように考えておくとよいでしょう。
yield from
として
transparent two way channel
呼び出し元と副生成物の間で
参考文献
関連
-
Python Pillow Image.save jpg画像圧縮問題
-
[解決済み】終了コード -1073741515 (0xC0000135)でプロセス終了)
-
[解決済み】インポートエラー。モジュール名 urllib2 がない
-
[解決済み] Pythonで型をチェックする標準的な方法は何ですか?
-
[解決済み] Python 3 の "python -m SimpleHTTPServer" に相当するものは何ですか?
-
[解決済み] Pythonの "assert "はどのように使うのですか?
-
[解決済み] Pythonが解釈される場合、.pycファイルとは何ですか?
-
[解決済み] Pythonの「名前付きタプル」とは何ですか?
-
[解決済み】type()とisinstance()の違いは何ですか?)
-
[解決済み】C#のyieldキーワードは何に使われるのか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
python string splicing.join()とsplitting.split()の説明
-
Pythonコードの可読性を向上させるツール「pycodestyle」の使い方を詳しく解説します
-
任意波形を生成してtxtで保存するためのPython実装
-
Python LeNetネットワークの説明とpytorchでの実装
-
Pythonの@decoratorsについてまとめてみました。
-
[解決済み】Python regex AttributeError: 'NoneType' オブジェクトに 'group' 属性がない。
-
[解決済み】インポートエラー。モジュール名 urllib2 がない
-
[解決済み】Python: OverflowError: 数学の範囲エラー
-
[解決済み】Python - "ValueError: not enough values to unpack (expected 2, got 1)" の修正方法 [閉店].
-
[解決済み] 末尾再帰とは何ですか?