私の意図は、キーがプリミティブであり、その値が文字列を返すゼロ引数の関数である辞書を作成することです。 (これは、VMを実装するためのより大きなプロジェクトの一部です)。これらの関数の中には、自明ではなく、手動で作成および割り当てられるものもあります。それらはうまく動作します。しかし、他のものは自動生成に適しているようです。python3を強制的に値渡しする方法はありますか?
私の最初の試みは失敗しました:
>>> 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')]
罰金、OK。ラムダ関数は呼び出されるまで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がやった時に変更されない独立変数を作成するだろうと思いました。それは事実ではないことが分かります。
この試みは明らかに機能しませんでした。たぶん、文字列上のコピーは、何もないですか?
>>> 's' is 's'
True
>>> a = 's'
>>> b = copy(a)
>>> a is b
True
>>> from copy import deepcopy
>>> b = deepcopy(a)
>>> a is b
True
右。文字列上のコピーは、無駄です。 Deepcopyはこれを修正しません。結果として、ラムダはまだ各ループで更新されている変数への参照を持ち、このバグを引き起こします。
私たちは別のアプローチが必要です。一時変数の静的変数に必要な変数を保存するとどうなりますか?各一時関数がそれ自身のアイデンティティを取得するなら、それはうまくいくはずです...
>>> 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'
...と:この時点で、私は手動でそれをすべて扱うの危機に瀕してよ。しかし、これはあきらめているように感じ、信じられないほど退屈なものになります。この作業を達成するための適切な方法がありますか?結局のところ、私がいつもPythonを好きな理由の1つは、手動のポインタ管理から遠ざかることです。私はポインタツールの完全なスイートが含まれていることを望んでいたことは想像もしませんでした!
ありがとうございます!デフォルトのパラメータを設定することは、make_const関数を通してすべてのものを与えることよりもはるかに意味があります。私は2つの方法の間にパフォーマンスに大きな違いはないと思いますか? – coriolinus
@coriolinus大きな違いはありません。もしあれば、ボトルネックになる前に揚げる魚がもっと多いかもしれません。その時点で、弾丸を噛んで、コード[RPython](http://morepypy.blogspot.de/2011/04/tutorial-writing-interpreter-with-pypy.html)を作成し、コンパイルしてください。 C、JITコンパイラ、さまざまな優れたGCをほぼ無料で提供しています。 – delnan