Python 可変引数定義されたクラスを継承するときの覚書


PythonのGUI(Tkinter)を使ってプログラムを書いていると、GUI Class継承する場合に
もれなく可変引数も継承されます。
しかし、継承先のClassで引数を追加すると、継承元でエラーが発生して使いづらい状況です。

例えば、TkinterのCheckbuttonは初期値を設定する事ができません。
初期値を設定できるようなCheckbuttonを作った際の覚書。

普通に記述すると、下記のようになります。

NormalCheckbox
cv = tk.BooleanVar()
cb = tk.Checkbutton(self, parent, variable=cv)
cv.set(True)  #初期値設定

しかし、私はこういう風に書きたい。

ShimplCheckbox
cb = tk.Checkbutton(self, parent, check=True)

そこで、tk.Checkbuttonを継承して、SimpleCheckを作ってみます

SimpleCheckbox.py
# Initial value = check=True or False
class SimpleCheck(tk.Checkbutton):
    def __init__(self, parent, *args, **kw):
        self.flag = kw.pop('check')
        self.var =  tk.BooleanVar()
        if self.flag:
            self.var.set(True)
        self.txt = kw["text"]
        tk.Checkbutton.__init__(self, parent, *args, **kw, variable=self.var)

    def get(self):
        return self.var.get()

しかし、このコードには問題があります。
それは、引数"check"を指定しなければエラーが発生するという問題です

mainloop
if __name__ == '__main__':
    app  = tk.Tk()
    sc1 = SimpleCheck(app, check=True, text="hoge")
    sc1.pack()
    sc2 = SimpleCheck(app)
    sc2.pack()

    print(sc1.getText())    
    print(sc1.cget('text'))#same result
    app.mainloop()
error
Traceback (most recent call last):
  File "arg_test.py", line 24, in <module>
    sc2 = SimpleCheck(app)
  File "arg_test.py", line 7, in __init__
    self.flag = kw.pop('check')
KeyError: 'check'

そこで可変引数を使った継承における、引数の取り出し方法を覚書として示す。

三項演算子を使った場合、"pass"を使うとエラーが出るようです。

SimpleCheck.py
import tkinter as tk

# Check value  :check=True or False (Default False)
# Label text   :text=Keword
class SimpleCheck(tk.Checkbutton):
    def __init__(self, parent, *args, **kw):
        self.flag = kw.pop('check') if('check' in kw) else False
        self.txt  = kw['text']      if('text' in kw) else ""
        self.var =  tk.BooleanVar()
        if self.flag:
            self.var.set(True)
        tk.Checkbutton.__init__(self, parent, *args, **kw, variable=self.var)

    def get(self):
        return self.var.get()

    def getText(self):
        return self.txt

if __name__ == '__main__':
    app  = tk.Tk()
    sc1 = SimpleCheck(app, check=True, text="hoge")
    sc1.pack()
    sc2 = SimpleCheck(app)
    sc2.pack()

    print(sc1.getText())    
    print(sc1.cget('text'))#same result
    app.mainloop()

追記@shiracamusさんからアドバイス頂きまして
三項演算子を使わなくてもDicのpop第二引数で初期値を設定できるようです。
アドバイスありがとうございました。

diff
    def __init__(self, parent, *args, **kw):
        self.flag = kw.pop('check', False)
        self.txt  = kw['text']  if('text' in kw) else ""