私の意図は、キーがプリミティブであり、値が文字列を返すゼロ引数関数である辞書を作成することです。(これは、VMを実装するためのより大きなプロジェクトの一部です。)これらの機能の一部は重要であり、手動で作成および割り当てられます。それらはうまく機能します。ただし、自動生成に適しているように見えるものもあります。
私の最初の試みは失敗しました:
>>> regs = ['a', 'b', 'c', 'x', 'y', 'z']
>>> vals = {i : lambda: r for i, r in enumerate(regs)}
>>> [(k, vals[k]()) for k in vals.keys()]
[(0, 'z'), (1, 'z'), (2, 'z'), (3, 'z'), (4, 'z'), (5, 'z')]
いいよ; ラムダ関数は、呼び出されるまでrを読み取りません。値を単独で分離しようとして、もう一度試しました。
>>> from copy import copy
>>> vals = {}
>>> i = 0
>>> for reg in regs:
... r = copy(reg) # (1)
... vals[i] = lambda: r
... i += 1
...
>>> [(k, vals[k]()) for k in vals.keys()]
[(0, 'z'), (1, 'z'), (2, 'z'), (3, 'z'), (4, 'z'), (5, 'z')]
(1)このステップにより、regが変更されても変更されない独立変数が作成されると思いました。そうではないことが判明しました。
そのため、その試みは明らかに機能しませんでした。たぶん、文字列上のコピーは、noopですか?
>>> 's' is 's'
True
>>> a = 's'
>>> b = copy(a)
>>> a is b
True
>>> from copy import deepcopy
>>> b = deepcopy(a)
>>> a is b
True
右。文字列のコピーは、noopです。Deepcopyはこれを修正しません。その結果、ラムダにはまだ各ループで更新されている変数への参照があり、このバグが発生します。
別のアプローチが必要です。必要な変数を一時関数の静的変数に保存するとどうなりますか?各一時関数が独自のIDを取得する場合、これは機能するはずです...
>>> vals = {}
>>> i = 0
>>> for reg in regs:
... def t():
... return t.r
... t.r = reg
... vals[i] = t
... i += 1
...
>>> [(k, vals[k]()) for k in vals.keys()]
[(0, 'z'), (1, 'z'), (2, 'z'), (3, 'z'), (4, 'z'), (5, 'z')]
いいえ。この時点で、私はすべてを手動で処理する寸前です。
>>> vals = {}
>>> vals[0] = lambda: 'a'
>>> vals[1] = lambda: 'b'
...など。しかし、これはあきらめているように感じ、信じられないほど退屈になります。このタスクを実行するための適切なpythonicの方法はありますか?結局のところ、私が通常pythonを愛する理由の1つは、手動のポインター管理から離れることができることです。ポインタツールの完全なスイートが含まれているとは想像もしていませんでした。