呼び出し部分が少し説明が必要かなと思ったので、
ジェネレーターを使った実装(サンプル)
python
1
2import tkinter as tk
3
4root = tk.Tk()
5text = tk.StringVar()
6label = tk.Label(root, textvar=text)
7label.pack()
8
9
10### [Step1] この関数を導入します
11def gen_timer(root, gen):
12 def _next():
13 interval = next(gen, None)
14 if interval is not None:
15 root.after(int(interval*1000), _next)
16 root.after_idle(_next)
17
18def game():
19 text.set("味方の攻撃!")
20 yield 1 ### [Step2] time.sleep(1) の部分を置き換え
21 text.set("敵に100のダメージ")
22
23### [Step3] 呼び出し方法を変更。
24gen_timer(root, game())
25
26### ボタンのイベントcommand 等に登録する際は、
27# イベント実行時に、gen_timer 関数が呼ばれるように構成する。
28# ジェネレータを作成するタイミングが異なる点が注意
29
30# 従来: 関数を登録していたところを
31# command=game
32# OK:
33# command=lambda: gen_timer(root, game())
34# NG: 2回目以降の呼び出しで、ジェネレーターが再利用されてしまう → 2回目以降反応しない
35# command=functools.partial(gen_timer, root, game())
36
37button = tk.Button(root, text="start")
38button.config(command=lambda:gen_timer(root, game()))
39button.pack()
40
41root.mainloop()
変更が必要な点は3箇所
- Step1: ユーティリティ関数の導入
- Step2: time.sleep -> yield へ変更
- Step3: 呼び出し部分の変更
※ functools.partial を使いたい場合は、
ジェネレータ生成を遅らせるように、少し工夫が必要です。
functools.partial -> lambda は殆どの場合、書き換えが可能です。
引数の順序をどうこうする、パズル的な難しさがありますが、
うまく使えると、記述を簡潔に出来たり実行効率を良くしたり出来ます。
それぞれ状況に応じて長所短所があるので、
確実な方法は、新たな関数を作る方法です。
python
1
2from functools import partial
3
4def gen_timer_func(root, func):
5 gen_timer(root, func())
6
7button.config(command=partial(gen_timer_func, root, game))
8
9
10## 引数を渡したい場合は、少し複雑になります。
11
12## functools.partial を使う場合
13make_game = partial(game, arg1, arg2)
14button.config(command=partial(gen_timer_func, root, make_game)
15
16## lambda を使う場合。記述はシンプルになりますが
17# 注意点: for文内で使うと想定した挙動にならない落とし穴があります。
18button.config(
19 command=lambda: gen_timer(root, game(arg1, arg2))))
20
21# arg1, arg2 がループ内で変化する変数の場合、このような対策が必要になる
22button.config(
23 command=lambda arg1=arg1, arg2=arg2: gen_timer(root, game(arg1, arg2))))
24
25## 関数
26# 無難な方法は(少し手間でも)関数を定義する方法です
27def start_game():
28 gen_timer(root, game(arg1, arg2))
29
30button.config(command=start_game)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/03/11 23:57