あなたが一般的に理解しているが、1つの小さな部分があなたを困惑させている機能を分解するための優れた方法は、Pythonデバッガーを使用することです. コメントを追加したものを次に示します。
-> def flatten(nested):
(Pdb) l
1 -> def flatten(nested):
2 try:
3 for sublist in nested:
4 for element in flatten(sublist):
5 yield element
6 except TypeError:
7 yield nested
8
9 import pdb; pdb.set_trace()
10 list(flatten([[1,2],3]))
11
(Pdb) a
nested = [[1, 2], 3]
上記では、関数を入力したばかりで、引数は[[1, 2], 3]
です。pdb のstep関数を使用して、遭遇する再帰呼び出しに関数をステップ実行しましょう。
(Pdb) s
> /Users/michael/foo.py(2)flatten()
-> try:
(Pdb) s
> /Users/michael/foo.py(3)flatten()
-> for sublist in nested:
(Pdb) s
> /Users/michael/foo.py(4)flatten()
-> for element in flatten(sublist):
(Pdb) s
--Call--
> /Users/michael/foo.py(1)flatten()
-> def flatten(nested):
(Pdb) a
nested = [1, 2]
flatten
引数が である の1 つの内部フレームに足を踏み入れました[1, 2]
。
(Pdb) s
> /Users/michael/foo.py(2)flatten()
-> try:
(Pdb) s
> /Users/michael/foo.py(3)flatten()
-> for sublist in nested:
(Pdb) s
> /Users/michael/foo.py(4)flatten()
-> for element in flatten(sublist):
(Pdb) s
--Call--
> /Users/michael/foo.py(1)flatten()
-> def flatten(nested):
(Pdb) a
nested = 1
2 つのフレームで、引数1
はもはや iterable ではありません。これは興味深いはずです…</p>
(Pdb) s
> /Users/michael/foo.py(2)flatten()
-> try:
(Pdb) s
> /Users/michael/foo.py(3)flatten()
-> for sublist in nested:
(Pdb) s
TypeError: "'int' object is not iterable"
> /Users/michael/foo.py(3)flatten()
-> for sublist in nested:
(Pdb) s
> /Users/michael/foo.py(6)flatten()
-> except TypeError:
(Pdb) s
> /Users/michael/foo.py(7)flatten()
-> yield nested
(Pdb) s
--Return--
> /Users/michael/foo.py(7)flatten()->1
-> yield nested
というexcept TypeError
わけで、引数自体を生成しているだけです。フレームアップ!
(Pdb) s
> /Users/michael/foo.py(5)flatten()
-> yield element
(Pdb) l
1 def flatten(nested):
2 try:
3 for sublist in nested:
4 for element in flatten(sublist):
5 -> yield element
6 except TypeError:
7 yield nested
8
9 import pdb; pdb.set_trace()
10 list(flatten([[1,2],3]))
11
yield element
はもちろん yield1
であるため、最下位のフレームが に達するTypeError
と、結果はスタックの一番外側のフレームまで伝播しflatten
、外側の iterable のさらに別の部分に移動する前に、結果が外の世界に渡されます。