Raspberry Pi & Python 開発ブログ ☆彡

Raspberry PiとPythonの基本的な使い方をわかりやすく解説。初心者、入門者必見!!

クラスの使い方 (実例)

ブログ管理者のP.Hです!

今回がオブジェクト指向の最後の記事になります。 実際にクラスをどのように使うのか、具体例を上げて説明したいと思います。 何となくオブジェクト指向について理解できているかな、 と感じている方はこの記事を読んでみてください。自分の理解度がわかるかもしれません。

それでは解説していきます。

継承はそんなに使わない?

少し話がそれますが、継承とimportについて記載しておこうと思います。

他のクラスの機能を使いたい場合、そのクラスを全て継承する必要があると思うかもしれませんが、 そうではありません。ただ使いたいだけであれば、使いたいクラスのpathを指定して記述すればいいだけです。

pathの指定には、importを使います。pythonの標準モジュールの場合は、importの後にクラス名を書くだけです。 自分や誰かが作成したクラスを使いたい場合は、importの後にpathを書きます。 下記はimportの書き方の一例になります。

import sys # 標準モジュール: sys を使いたい場合
from testFolder.testFile import testClass # testFolderというフォルダの中にあるtestFile.pyの中のtestClassを使いたい場合

継承を使う場合

  • 既にクラスが存在し、その機能を引き継いで新しい機能を追加したクラス or 一部機能を変更したクラスを作る時
  • 多様性を使う時

importを使う場合

  • クラスの機能をただ使いたい時
  • 標準モジュールの場合は、importの後にクラス名を書く
  • 自分や誰かが作成したクラスを使いたい場合は、importの後にpathを書く


自分で新規のクラスを作る時は、継承するようなクラスがないため、継承を使うことは少ないかもしれません。 オブジェクト指向を勉強し、継承をいっぱい使いたいと思うかもしれませんが、 新規でプログラムを作る時、継承はあまり使わないのです。

複数のクラスで同じクラスを使いたい場合

Queueというよく使うクラスがあります。ここではQueueクラスについては詳しく説明しませんが、 putという関数で値を受け取り、getという関数で値を取り出すことができます。

MyClassAというクラスの中のput関数で値を受け取り、MyClassBというクラスでget関数で値を取り出したい場合は、 MyClassAとMyClassBのクラスで同じQueueクラスを持っている必要があります。 感がいい人は気づいたかもしれませんが、それぞれのクラスにQueueの先頭アドレスを渡せば良いのです。
下記のようにコードを書けば、MyClassAとMyClassBのクラスに同じQueueクラスを渡すことができ、 MyClassAとMyClassBクラスの間でデータのやり取りをすることができます。

import queue

class MyClassA():

    def __init__(self, q):
        self.q = q

    def put(self, word):
        self.q.put(word) # q(Queue)に格納されているデータを格納

class MyClassB():

    def __init__(self, q):
        self.q = q

    def get(self):        
        data = self.q.get() # q(Queue)に格納されているデータを取り出す
        print(data)

q = queue.Queue() # Queueクラスをインスタンス化し、MyClassA,Bの両方に渡す

# 同じqのメモリの先頭アドレスを渡している
# MyclassAとMyClassBのqは同じもの
a = MyClassA(q)
b = MyClassB(q)

a.put("test") # qに"test"というデータを格納する
b.get() # qからデータを取り出す。testと表示される。

MyClassAクラスとMyClassBクラスのデータのやり取りがとても分かりやすく実現できます。 MyClassAクラスとMyClassBクラスをthreadやmultiprocessで使うと更に便利でしょう。

オブジェクト指向のまとめ(最終)

オブジェクト指向という大きい視点から、私が伝えたいのは以下のふたつです。

  • カプセル化、継承、多様性はプログラミングという非常に複雑なものを整理し管理しやすく手法である
  • クラス、関数、変数全てにおいてメモリの先頭アドレスを意識することで、コーディングの理解が深まる

少しでも読者の役に立てていれば幸いです。 オブジェクト指向の説明については、以上になります。

おまけ

少し難しくなりますが、スレッドを使った実用的なqueueの使い方の例を書いておきます。

from concurrent.futures import ThreadPoolExecutor 
import queue
import time
import random

class MyThread1:

    def __init__(self, q):
        self.q = q

    def run(self):

        while True:

            # 温湿度、二酸化炭素濃度を測定する等のコードをここに書き、データを取得する 
            # 取得したデータをqueueに格納する。

            data = random.randint(0,30) # 例なので、ランダムなデータを生成
            self.q.put(data)

            time.sleep(10) # 10秒ごとに測定

class MyThread2:

    def __init__(self, q):
        self.q = q

    def run(self):

        while True:

            data =self.q.get()
            print(data) # 例なので、qのデータを表示

            # qのデータをWebに送信、csvに保存する等のコードをここに書く。

if __name__ == "__main__":
    
    q = queue.Queue() 

    th_pool = [] # スレッド生成したい関数を登録
    th_pool.append(MyThread1(q).run) # MyThread1のrun関数をリストに追加
    th_pool.append(MyThread2(q).run) # MyThread2のrun関数をリストに追加
        
    with ThreadPoolExecutor(max_workers=2) as executor:
        for th in th_pool:
            results = executor.submit(th) # submit関数で、list内の関数をスレッド生成
        for result in results:
            print(result)