2017-12-09 9 views
0

最近私はPythonを使い始めました。最初のプロジェクトで電卓を作ってみたかったので、ボタンをループで追加することにしました。しかし、ボタンのコールバックは常にコールバック関数の引数として渡したい変数の最後の状態です。ここに私のコードです。動的にボタンコールバックを割り当てる - Python

def addButtons(): 
buttons = [] 

label = "" 
num = 0 

posX = 4 
posY = 1 

for i in range(12): 

    if (i % 4 < 3): 
     num += 1 
     label = str(num) 
    else: 
     label = "Blank" 

    if (i % 4 == 0): 
     posY += 1 

    if (posX < 3): 
     posX += 1 
    else: 
     posX = 0 

    buttons.append(
     Button(buttonPanel, text=label, command=lambda: function(i), relief="flat", borderwidth=0, sticky=w, background="#fff", activebackground="#eee")) 
    buttons[i].grid(column=posX, row=posY, sticky=N + S + E + W) 

    buttonPanel.grid_columnconfigure(posX, weight=1) 
    buttonPanel.grid_rowconfigure(posY, weight=1) 

    functions.append(label) 


def function(obj): # the button's functions are identified by this function and executed respectively 
    print obj 

私がボタンをクリックすると、私はいつもコンソールから11を得る。コールバックパラメータを動的に設定できる方法はありますか?任意の助け ため

おかげ - ヤコブ

答えて

0

は、あなたが持っている問題は、あなたがlambda: function(i)を書くとき、ラムダ関数はiの現在の値を保存していないということです。むしろ、それは呼び出されるときに外側の名前空間でのみ検索します。そのため、すべてのコールバックで最後の値iが表示されます。なぜなら、それが最後に変更されたときの値だったからです。あなたはラムダに特定の値に名前iを結合することによって、この問題を回避することができ

lambda i=i: function(i) 

これがデフォルト引数の虐待の一種であるが、それは正確に何をしたいん。外部ネームスペース内のiの現在の値は、ラムダ関数のネームスペース内の別のi変数のデフォルト値としてバインドされます。これはラムダが定義されているときに発生するので、後で外部名前空間のiが値を変更しても問題ありません。

本質的に同じことをする別の方法は、標準ライブラリのfunctoolsモジュールで定義されたpartialタイプを使用することです。後で呼び出すことができる関数にいくつかの引数をバインドすることができます。後でいくつかの追加の引数が必要な場合に最も便利ですが、この状況でも役立ちます。ラムダの代わりに、partial(function, i)をコールバックとして渡します。

+0

完璧に動作します、ありがとうございました! –

関連する問題