Poke-Controllerで1つのスクリプトから別のスクリプトを呼び出す

Poke-Controllerとは

Nintendo Switchを自動化できるツールのことです。

スクリプトって?

スクリプトとは、Poke-Controllerで実行できるpyファイルのことです。pokecon用プログラムと表現されたりしてます。(違ったらごめんなさい)

classの継承

今回の技を取得するにあたって、pythonのclassの機能である、継承について知っておく必要があります。継承に加え、importについても知識が必要です。(難易度高杉)

本題

記事のタイトルの通りです。プログラムの開発側としてはうまく扱えば良いプログラムが作れるようになると思います。
手順を以下に記載します。ざっくり書くとなんと5つ手順で終わります。

  1. スクリプトを2つ用意する

  2. 継承させたいスクリプトをimportする

  3. クラス継承を行う

  4. 継承したスクリプトのinitを呼び出す

  5. 目的の関数を実行

さっそくですが、例をみていきましょう。

継承例(そのままでは使えません)

#       ↓継承元スクリプトのディレクトリ              ↓継承元class名
from Commands.PythonCommands.InputSerial import InputSerialKeyboard
from Commands.PythonCommands.Switch_keyboad import InputKeyboard

# 継承はImageProcPythonCommandを含めて最大3つまで
class AutoSerialcode(ImageProcPythonCommand,InputSerialKeyboard,InputKeyboard):
    NAME = 'スクリプト名'

    def __init__(self, cam, gui=None):
        super().__init__(cam)
        # 継承元のinitを呼び出す 継承元の変数名などは重複がないようにしておく
        super(InputKeyboard).__init__()
        super(InputSerialKeyboard).__init__()

    def do(self):
        # 継承元の関数を呼び出す 継承をしているので、self.○○で呼び出し可能
        self.keyboad_input(input_str='こちゃてす')
        self.typein_Serial(self.CODE_2[self.count])

ポイント1

継承したいスクリプトのほうでは、self.doを呼び出したい関数に設定しないこと
こちらはpythonの継承という機能の影響で、呼び出し元のスクリプト内と継承元のスクリプトに同じ名前の関数があると呼び出し元のスクリプトの関数が実行されてしまいます。

つまり、self.do内で実行してたものを関数として置き換える必要があるということです。以下のようなイメージです。

    def do(self):
        self.typein_Serial('GENNGER0GE94')


    def typein_Serial(self,input_code='TEST'):
     print(input_code)

ポイント2

#        ↓継承元スクリプトのディレクトリ              ↓継承元class名
from Commands.PythonCommands.InputSerial import InputSerialKeyboard

外部のプログラムを使えるようにするimportと同じ感じで、継承させたいスクリプトのclassをimportします。

ポイント3

class 継承先のclass名(ImageProcPythonCommand,継承元class名1,継承元class名2):
    NAME = 'スクリプト名'

importしたclassを用いて継承を行います。class名を括弧内にコピるだけです。最強のおまじないです。

ポイント4

super(継承元クラス名).__init__()

継承先class内に記述します。この処理は継承元のclassのinitを呼び出すことができます。継承元のinitを呼び出す理由としては、
ImageProcPythonCommandやPythonCommandなどのPokecon用の関数を含んだclassを使えるようにするためです。また、継承元のinit内で定義している変数を読み込む役割もあります。

夢のようですが..…

実は大きな落とし穴がございます。たまげたなあ

変数情報がスクリプト同士で共有される

self.○○で変数を定義している場合(関数も同様なことが起こります)、定義されている変数名と同じ名前の変数が継承元のスクリプトと継承先のスクリプトの両方に存在していると値を共有してしまうんですね。pythonの継承とはそんなものです。
変数情報が予期しないタイミングで共有されてしまうと個別で動かせていたスクリプトが継承をさせると動かなくなります。ここは結構ハマりました。

なので、self.○○で定義している変数はとくに気を付けてねって話です。

さらに問題点が….

なんとclassがそのまま読み込まれてしまうためか、まったく同じ名前のスクリプトがプログラム一覧に表示されてしまいます….

名前の重複を改善する(2022/10/03追記)

CommandLoader.pyを編集します。
スクリプト一覧はリストで管理されているため、その重複を消し去ればいいわけです。set関数を用いると重複を消すことができます。

    def getCommandClasses(self):
        classes = []
        for mod in self.modules:
            classes.extend([c for c in util.getClassesInModule(mod) \
                            if issubclass(c, self.base_type) and hasattr(c, 'NAME') and c.NAME])

        classes = list(set(classes)) # 追加した1行
        return classes

こんなことする必要ある?

メリットはもちろんあります。こうすることで、個別でそのスクリプトを使いたいときに使用ができるのです。
まったく同じプログラムだけど、他のプログラムに埋め込むのが大変(コード長すぎワロタ)、コピっただけなのになぜか動かない…..そんな問題も解決しやすいです。
ぜひ活用してみてください。

実装例

https://x.com/subKocha114514/status/1566557238298574848?s=20


以上


下記のX(旧Twitter)にて更新情報などを発信しています。
(最近はサブ垢にいますが....)
感想などをリプやメンション、DMしていただけると喜びます。

☆---------------------------------------------------------------------------------☆
最新情報はX(旧Twitter)で確認してください。
https://twitter.com/kochatece12

こちゃてすプログラム置き場
ポケモン剣盾、モンハンライズやその他自動化プログラムを配布しています。

Amazonほしいものリスト

☆---------------------------------------------------------------------------------☆


この記事が気に入ったらサポートをしてみませんか?