しょっちゅう忘れることを書いておく。
![]() |
66 |
557 views
クラスが依存するクラスは引数でもらうタイプの実装方法。
ミソなのはinterfaceを介するクラスを前提とすることで、期待していないクラスを指定できないようにできる。
下の例で言えば、引数に渡されるクラス、tearcherとstudentにはstand_upが定義されていることを期待している。
基本的な書き方は以下。
TyoureiControllerのinitで、isinnstanceでチェックを行い、interfaceが継承されているクラスかどうかをチェックする。
javaとかだとコンパイルエラーで弾けるけど、pythonは動かすまでわからないところがちょっと残念だけど、仕方なし。
PycharmなどのIDEがあれば、エラー表示はしてくれる。
- # coding: UTF-8
- from abc import ABC, ABCMeta, abstractmethod
- import inject
- class PersonInterface(ABC):
- """
- 人クラスのインターフェース
- """
- @abstractmethod
- def stand_up(self):
- print("立ち上がりました")
- class Student(PersonInterface):
- def __init__(self):
- pass
- def stand_up(self):
- # override
- print("しゃんと立ち上がりました")
- class Teacher(PersonInterface):
- def __init__(self):
- pass
- def stand_up(self):
- # override
- print("腰が重そうに立ち上がりました")
- class TyoureiController:
- def __init__(self, teacher: PersonInterface, student: PersonInterface):
- if not isinstance(teacher, PersonInterface):
- raise Exception("teacherがPersonInterfaceではありません")
- if not isinstance(student, PersonInterface):
- raise Exception("studentがPersonInterfaceではありません")
- self.teacher = teacher
- self.student = student
- def start(self):
- self.teacher.stand_up()
- self.student.stand_up()
- def main():
- teacher = Teacher()
- student = Student()
- con = TyoureiController(teacher, student)
- con.start()
- if __name__ == '__main__':
- main()
ただ、この書き方だとTyoureiControllerにteacher,student以外にも、parentやPTAなどの渡すクラスが増えたときに引数が増えて汚いと思う人もいる。
そんな人はinjenctを使ってまとめて渡すことができる。
と思ってサンプルを作ったが、これはエラーになる。
- # coding: UTF-8
- from abc import ABC, ABCMeta, abstractmethod
- import inject
- class PersonInterface(ABC):
- """
- 人クラスのインターフェース
- """
- @abstractmethod
- def stand_up(self):
- print("立ち上がりました")
- class Student(PersonInterface):
- def __init__(self):
- pass
- def stand_up(self):
- # override
- print("しゃんと立ち上がりました")
- class Teacher(PersonInterface):
- def __init__(self):
- pass
- def stand_up(self):
- # override
- print("腰が重そうに立ち上がりました")
- class TyoureiController:
- @inject.params(teacher=PersonInterface, student=PersonInterface)
- def __init__(self, teacher: PersonInterface, student: PersonInterface):
- if not isinstance(teacher, PersonInterface):
- raise Exception("teacherがPersonInterfaceではありません")
- if not isinstance(student, PersonInterface):
- raise Exception("studentがPersonInterfaceではありません")
- self.teacher = teacher
- self.student = student
- def start(self):
- self.teacher.stand_up()
- self.student.stand_up()
- def inject_config(binder):
- binder.bind(PersonInterface, Teacher())
- binder.bind(PersonInterface, Student())
- def main():
- #teacher = Teacher()
- #student = Student()
- inject.configure(inject_config)
- con = TyoureiController()
- con.start()
- if __name__ == '__main__':
- main()
エラーメッセージは以下。
- raise InjectorException('Duplicate binding, key=%s' % cls)
- inject.InjectorException: Duplicate binding, key=<class '__main__.PersonInterface'>
同じインターフェースを継承していることが原因。
こうすると直る。
- # coding: UTF-8
- from abc import ABC, ABCMeta, abstractmethod
- import inject
- class PersonInterface(ABC):
- """
- 人クラスのインターフェース
- """
- @abstractmethod
- def stand_up(self):
- print("立ち上がりました")
- class DummyInterface(ABC):
- @abstractmethod
- def stand_up(self):
- print("ダミーが立ち上がりました")
- class Student(DummyInterface):
- def __init__(self):
- pass
- def stand_up(self):
- # override
- print("しゃんと立ち上がりました")
- class Teacher(PersonInterface):
- def __init__(self):
- pass
- def stand_up(self):
- # override
- print("腰が重そうに立ち上がりました")
- class TyoureiController:
- @inject.params(teacher=PersonInterface, student=DummyInterface)
- def __init__(self, teacher: PersonInterface, student: DummyInterface):
- if not isinstance(teacher, PersonInterface):
- raise Exception("teacherがPersonInterfaceではありません")
- if not isinstance(student, DummyInterface):
- raise Exception("studentがPersonInterfaceではありません")
- self.teacher = teacher
- self.student = student
- def start(self):
- self.teacher.stand_up()
- self.student.stand_up()
- def inject_config(binder):
- binder.bind(PersonInterface, Teacher())
- binder.bind(DummyInterface, Student())
- def main():
- #teacher = Teacher()
- #student = Student()
- inject.configure(inject_config)
- con = TyoureiController()
- con.start()
- if __name__ == '__main__':
- main()
ようするにstudentのinterfaceをPersonInterfaceからDummyInterfaceに変更した。
これが良いのか悪いのかはちょっと微妙。
同じインターフェースだけど違うクラスを指定したときはエラーというのはDIの原則とかでエラーなのか、pythonのプログラムとしてただできないだけの問題なのかがわからない。
Page 38 of 69.
すぺぺぺ
本サイトの作成者。
プログラムは趣味と勉強を兼ねて、のんびり本サイトを作っています。
フレームワークはdjango。
ChatGPTで自動プログラム作成に取り組み中。
https://www.osumoi-stdio.com/novel/