アットウィキロゴ

python - 電卓(説明)

はじめに


pythonを用いて、電卓を作成した。初めてのGUIだったこと、また、オブジェク
ト指向プログラミングを勉強中という事で、見苦しいところがあるが、温かい目
で見て頂きたい。

コード全文 : python - 電卓

classについて


今回のコードはclassオブジェクトを多用している。classオブジェクトを使用す
ることのメリットを正確には理解できていないが、私が感じたことを以下に述べ
ていく。

第一に、コードを使いまわすことが出来る。このプログラムで言うのならば、ボ
タンを作成するコードはボタンの分だけ必要になる。これをclassを使用するこ
とでコードを減らすことが出来る。ボタン1とボタン2があるとしよう。二つのボ
タンは押された時に表示する文字が異なるだけで、大きさや色などの仕様は同じ
である。この場合、共通する仕様を予めコード化し、異なる部分だけ、個別に追
加すれば良い。このようにすれば、共通部分のコードをボタンの分だけ書く必要
性がなくなる。

第二に、後からの修正が容易であることが挙げられる。ボタンの設定を変更した
い場合、それもすべてのボタンに対して行いたい場合、classではボタンを設定
している部分のコードのみを書き換えれば良い。各ボタンごとにコードを書いて
いる場合は、各ボタンの設定を書き換える必要が出てきてしまい、面倒だ。

第三にコードが読みやすい。これは、ボタンやラベルに関しての設定がまとまっ
て記述されているため、その部分を読めば、何が原因で不具合が生じたのか、ま
たどこを書き換えればより良くなるのかが分かる。

次に実際のclassを用いたコードを見てみる。

class A:
    def __init__(self, A, B):
        self.a = A
        self.b = B

    def Display(self):
        print "+ : {0}".format(self.a + self.b)
        print "- : {0}".format(self.a - self.b)

instance = A(1, 2)
instance.Display()

1行目でクラスを宣言する。Aはクラスの名前で、基本的には、内容を表すような
名前にするべきだと考える。

2行目と6行目に記述されている、`def`はメソッドの作成である。クラスの内部
に存在する、関数のようなものである。メソッドはクラスの外部からも内部から
もアクセスすることが出来る。メッソドを実行すると、メソッド内に記述されて
いるコードが実行される。

特に、2行目に記述されている、`init`はクラスが呼び出された時に、特にメソ
ッドを実行するような記述なしに、実行される。初期化メソッドである。このコ
ードの場合、11行目でクラスAのインスタンスとして、instanceを作成している。
この時に、`init`内部のコードが実行される。3、4行目の'self.a'や'self.b'は
インスタンス変数と呼ばれるものである。クラス内部でインスタンス変数を参照す
る場合は'self.a'と書く。クラスの外部から参照する場合、`インスタンス名.a`
とする。つまりここでは'instance.a'とすれば、値を参照できる。インスタンス
変数はインスタンスごとに保持するため、仮にインスタンスが'instance'と
'instancecopy'がある場合、`instance.a`と'instancecopy.a'は別の変数を参
照することになる。

11行目のように記述することで、インスタンスを作成できる。また、`init`が引
数を取るのでそれを記述している。メソッドは、クラス内部でメソッドを使用す
る場合、`self.Display()`とする。外部から行う場合、`instance.Display()`と
する。

電卓作成に関する各部分の説明


文中に行数を指定し、説明する箇所があるがそれはコード全文(python - 電卓)
の箇所を示すものである。

import


from Tkinter import *
import Tkinter as tk

importするモジュールはTkinterである。このようにしないとうまくいかなかった。
明確な理由は不明だが、とりあえず、このようにimportした。

frame


class Use_Frame(ttk.Frame): 
    def __init__(self, master=None):
        ttk.Frame.__init__(self, master) 
        self.grid(column=0, row=0)

まず、GUIの基盤となるフレームクラスを作成する。このフレームの上に、ボタ
ンやラベルを配置する。8行目では、クラスの継承を行っている。ttk.Frameとい
うクラスを、自分の作成したクラスUse\_Frameに継承している。これで、
ttk.Frameに含まれているメソッドが使用できる。9行目以下の'init'部分で初期
化を行う。10行目で、フレームの作成、11行目でフレームの配置、13行目でフレー
ムの設定を行う。

9行目、10行目にある'master'は調べたが不明である。推測として、このオブジェ
クトの所属している場所を示していると考える。フレームの上にボタンやラベル
を乗せるが、この時、どのフレームに乗せるかを明示的にしなければならない。
フレームの場合も、どのGUIのフレームかということを明示的にする必要がある。
仮に、GUIの名前をdentakuだとすると、dentakuの中にフレーム(Frame1,Frame2...)
があり、フレームの中にボタン(Button1, Button2...)がある。Frame1に
Button1を乗せる場合、Button1のmasterはFrame1、Frame1のmasterはdentaku
ということになる。

11行目にある、gridメソッドは、フレームを格子状に配置する。columnが行、row
が列である。

button


class Use_Button(tk.Button):
    def __init__(self, master=None):
        tk.Button.__init__(self, master)

        self["height"] = 3
        self["width"] = 6
        self["font"] = ("Helvetica", 15)
        self["command"] = self.input_exe

    def input_exe(self):
        Label.push_list.append(self["text"])

        if self["text"] == "=":
            self.cal()
            Label.push_list = []

        elif self["text"] == "C":
            Label.push_list = []
            Label.Display()
            
        else:
            Label.Display()

    def cal(self):
            result = eval(Label.display_item)
            Label.push_list.append(str(result))
            Label.Display()        

ボタンクラスもフレームクラスと同じように、tk.Bottonを継承させる(16行目)。
17、18行目の'init'部分も同様に、ボタンの作成と、自ら設定する初期設定であ
る。20行目から23行目はボタンの性質を設定する。もちろん、フレームクラスと
同様に、configureを使用して設定を行うことも出来る。ここでは読みやすくす
るためにこのような書き方をする。

`self.[key]`とする事で、self(つまり、インスタンス)が持つディクショナリへ
アクセスする。`height`は高さ、`width`は幅、`font`はボタン上に書く文字の
フォント、`command`はボタンが押された時の処理を、それぞれ設定する。

25行目から37行目はボタンが押された時に実行されるメソッドである。

26行目の'Label.push_list'は次に説明を行う、ラベルクラスのインスタンスで
ある'Label'にアクセスしている。このような書き方が正しいのか不明である。
使用する際は気をつけるべきだと考える。この行が行っていることは「インスタ
ンス(Label)が持つインスタンス変数push_listにself['text']を追加する」であ
る。

self['text'](ディクショナリ)はボタンに書かれた文字である。電卓では数字や
演算子のボタンを作るが、そのボタン上にかかれている文字列が代入されている。

28行目以下のif文は、押されたボタンに対して処理の分岐を行う。self['text']
の値によって処理を変える。特に、`=`と'C'は他のボタンとは別の処理を行いた
いので個別に設定を行う。

39行目以下は計算を行うメソッドである。40行目のevalは文字列を数式として処
理する関数である。例えば'1 + 1'はeval(`1 + 1`)で処理すると2になる。

label


class Use_Label(tk.Label):
    def __init__(self, master=None):
        tk.Label.__init__(self, master)

        self["font"] = ("Helvetica", 20)
        self["width"] = 20
        self["anchor"] = "e"
        self.push_list = []

    def Display(self):
        self.display_item = "".join(self.push_list)
        self["text"] = self.display_item

46行目から48行目はフレームクラスとボタンクラスと同様の処理である。
tk.Labelを継承している。

50行目から53行目は初期設定である。ボタンクラスでは出てこなかった'anchor'
はラベルの中にある文字をどのように配置するか、つまり、左からなのか右から
なのか、中央に置くのか等を設定する。`e`はeastで東の意味なので、右から文
字を置いていく。

53行目の'self.push_list'はインスタンス変数を作成している。ここに、他の
クラスからアクセスしていた。

55行目以降はメソッドである。自身の'text'、コード中ではself['text']を変
化させる。ボタンクラスからアクセスされていた。

57行目にある"".join()は()にリストを置くことで、任意の文字("ここの文字列")を
使用し、リストの各要素を結合する。例えば、

>>> ".".join(["test", "txt"])
>>> "test.txt"

>>> "/".join(["desktop", "test.txt"])
>>> "desktop/test.txt"

このようになる。単に結合したい場合、"".join()として""の中に何も入れない。

root = Tk()
root.title("計算機")

62行目はウィンドウを作成する。これもTk()クラスのインスタンスを作成し、
その中のメソッドを63行目で使用する。63行目はウィンドウのタイトルを設定
するメソッドである。

71行目以下は、クラスを呼び出して、各オブジェクトを配置していく。
最終更新:2018年03月01日 16:22