1

次の例を検討してください。

def fn(x):
    if x > 2:
        raise StopIteration
    return x
results = list(map(fn, range(5)))
print(results)

これを python 2 で実行すると、期待どおりの結果が得られます。

Traceback (most recent call last):
  File "example.py", line 5, in <module>
    results = list(map(fn, range(5)))
  File "example.py", line 3, in fn
    raise StopIteration
StopIteration

しかし、python3で実行するとStopIteration例外でプログラムが終了しません。次の結果が出力されます。

[0, 1, 2]

mapPython 3 (具体的には python 3.5.1)の関数はStopIteration、提供された iterable が例外をスローしたかのように、例外をキャッチして処理するようです。これはバグですか?

4

2 に答える 2

1

なぜこれが起こるのかは明らかだと思います:fnスローすると、反復する要素がもうないときに、python はこれを反復子によってスローされるべき反復の終わりとして誤って解釈します (この例外がこの特別な役割を果たすことを知っていると思います反復プロトコル)。

Python2 はmap最初に try/catch ブロックのイテレータから値を取り出してから、それを処理するだけだと思いますfn(ここでは try/catch はありません)。Python3 (lazy)mapはおそらくエラーの try/catch について何もしませんfn

これは Python3 のバグですか? map最初に、これを修正すると、イテレータからのすべてのプルを try-catch する必要があるため、パフォーマンスがかなり低下する可能性があることに注意してください。これは、無害な修正は、おそらく、StopIteration目的以外の目的での使用を明示的に禁止することです.

そのようなメモがいくつかのPEPにもある可能性があります:)

于 2016-05-21T20:03:34.193 に答える
1

@thebjorn がコメントで述べたように、Python 3 では遅延 (技術用語)であるため、エラーはmap()from ではなく から発生します: 関数自体は呼び出されません。list()map()

代わりに、イテレータを返し、それが によって消費されlist()ます。

この例を見てみましょう:

>>> def fn(x):
...     if x > 2:
...         raise Exception()
...     return x
... 
>>> results = map(fn, range(5))
>>> results = list(results)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in fn
Exception

ご覧のとおり、 を呼び出すと例外が発生します。これは、カスタム関数が呼び出されるイテレータを読み取るlist()ためです。list()

于 2016-05-21T15:22:56.983 に答える