3

だからここに私が取り組んできたものを単純化するいくつかのコードがあります:

vars = {
    'a':'alice',
    'b':'bob',
}
cnames = ['charlie', 'cindy']

commands = []

for c in cnames:
    kwargs = dict(vars)
    kwargs['c'] = c
    print kwargs
    commands.append(lambda:a_function(**kwargs))

print commands

def a_function(a=None, b=None, c=None):
    print a
    print b
    print c

for c in commands:
    print "run for "+ repr(c)
    c()

そして、ここにその出力があります:

{'a': 'alice', 'c': 'charlie', 'b': 'bob'}
{'a': 'alice', 'c': 'cindy', 'b': 'bob'}
[<function <lambda> at 0x1001e9a28>, <function <lambda> at 0x1001e9e60>]
run for <function <lambda> at 0x1001e9a28>
alice
bob
cindy
run for <function <lambda> at 0x1001e9e60>
alice
bob
cindy

チャーリー、次にシンディを期待しますが、なぜシンディが2回表示されるのですか?

4

2 に答える 2

5

古典的なバインド時間の問題が発生しています.@Mikeの解決策は古典的なものです. 良い代替案は、高階関数を書くことです:

def makecall(kwargs):
  def callit():
    return a_function(**kwargs)
  return callit

commands.append(makecall(kwargs))ループで使用します。両方のソリューションは同じ原則で機能します (引数の通過を通じて早期バインディングを強制することにより、私の場合は単純な引数であり、@Mike の名前付き引数のデフォルト値です)。どちらを選択するかは、スタイルかエレガンスの問題です (私は、lambda非常に単純なケースでは許容しますが、最も微妙な複雑さが介在する限り、古き良きものを大いに好みdefます ;-)。

于 2010-06-24T04:35:59.837 に答える
4

関数が呼び出されるまで、関数の本体は実行されません。を実行するとlambda: a_function(**kwargs)、実際に関数を呼び出すkwargsまで検索されません。その時点で、ループで最後に作成したものに割り当てられます。

あなたが望む結果を得る1つの解決策はすることですcommands.append(lambda kwargs=kwargs: a_function(**kwargs))

于 2010-06-24T04:28:36.987 に答える