python

しょっちゅう忘れることを書いておく。

66

557 views

クラスが依存するクラスは引数でもらうタイプの実装方法。
ミソなのはinterfaceを介するクラスを前提とすることで、期待していないクラスを指定できないようにできる。
下の例で言えば、引数に渡されるクラス、tearcherとstudentにはstand_upが定義されていることを期待している。

基本的な書き方は以下。
TyoureiControllerのinitで、isinnstanceでチェックを行い、interfaceが継承されているクラスかどうかをチェックする。
javaとかだとコンパイルエラーで弾けるけど、pythonは動かすまでわからないところがちょっと残念だけど、仕方なし。
PycharmなどのIDEがあれば、エラー表示はしてくれる。

  1. # coding: UTF-8
  2. from abc import ABC, ABCMeta, abstractmethod
  3. import inject
  4. class PersonInterface(ABC):
  5. """
  6. 人クラスのインターフェース
  7. """
  8. @abstractmethod
  9. def stand_up(self):
  10. print("立ち上がりました")
  11. class Student(PersonInterface):
  12. def __init__(self):
  13. pass
  14. def stand_up(self):
  15. # override
  16. print("しゃんと立ち上がりました")
  17. class Teacher(PersonInterface):
  18. def __init__(self):
  19. pass
  20. def stand_up(self):
  21. # override
  22. print("腰が重そうに立ち上がりました")
  23. class TyoureiController:
  24. def __init__(self, teacher: PersonInterface, student: PersonInterface):
  25. if not isinstance(teacher, PersonInterface):
  26. raise Exception("teacherがPersonInterfaceではありません")
  27. if not isinstance(student, PersonInterface):
  28. raise Exception("studentがPersonInterfaceではありません")
  29. self.teacher = teacher
  30. self.student = student
  31. def start(self):
  32. self.teacher.stand_up()
  33. self.student.stand_up()
  34. def main():
  35. teacher = Teacher()
  36. student = Student()
  37. con = TyoureiController(teacher, student)
  38. con.start()
  39. if __name__ == '__main__':
  40. main()

ただ、この書き方だとTyoureiControllerにteacher,student以外にも、parentやPTAなどの渡すクラスが増えたときに引数が増えて汚いと思う人もいる。
そんな人はinjenctを使ってまとめて渡すことができる。

と思ってサンプルを作ったが、これはエラーになる。

  1. # coding: UTF-8
  2. from abc import ABC, ABCMeta, abstractmethod
  3. import inject
  4. class PersonInterface(ABC):
  5. """
  6. 人クラスのインターフェース
  7. """
  8. @abstractmethod
  9. def stand_up(self):
  10. print("立ち上がりました")
  11. class Student(PersonInterface):
  12. def __init__(self):
  13. pass
  14. def stand_up(self):
  15. # override
  16. print("しゃんと立ち上がりました")
  17. class Teacher(PersonInterface):
  18. def __init__(self):
  19. pass
  20. def stand_up(self):
  21. # override
  22. print("腰が重そうに立ち上がりました")
  23. class TyoureiController:
  24. @inject.params(teacher=PersonInterface, student=PersonInterface)
  25. def __init__(self, teacher: PersonInterface, student: PersonInterface):
  26. if not isinstance(teacher, PersonInterface):
  27. raise Exception("teacherがPersonInterfaceではありません")
  28. if not isinstance(student, PersonInterface):
  29. raise Exception("studentがPersonInterfaceではありません")
  30. self.teacher = teacher
  31. self.student = student
  32. def start(self):
  33. self.teacher.stand_up()
  34. self.student.stand_up()
  35. def inject_config(binder):
  36. binder.bind(PersonInterface, Teacher())
  37. binder.bind(PersonInterface, Student())
  38. def main():
  39. #teacher = Teacher()
  40. #student = Student()
  41. inject.configure(inject_config)
  42. con = TyoureiController()
  43. con.start()
  44. if __name__ == '__main__':
  45. main()

エラーメッセージは以下。

  1. raise InjectorException('Duplicate binding, key=%s' % cls)
  2. inject.InjectorException: Duplicate binding, key=<class '__main__.PersonInterface'>

同じインターフェースを継承していることが原因。

こうすると直る。

  1. # coding: UTF-8
  2. from abc import ABC, ABCMeta, abstractmethod
  3. import inject
  4. class PersonInterface(ABC):
  5. """
  6. 人クラスのインターフェース
  7. """
  8. @abstractmethod
  9. def stand_up(self):
  10. print("立ち上がりました")
  11. class DummyInterface(ABC):
  12. @abstractmethod
  13. def stand_up(self):
  14. print("ダミーが立ち上がりました")
  15. class Student(DummyInterface):
  16. def __init__(self):
  17. pass
  18. def stand_up(self):
  19. # override
  20. print("しゃんと立ち上がりました")
  21. class Teacher(PersonInterface):
  22. def __init__(self):
  23. pass
  24. def stand_up(self):
  25. # override
  26. print("腰が重そうに立ち上がりました")
  27. class TyoureiController:
  28. @inject.params(teacher=PersonInterface, student=DummyInterface)
  29. def __init__(self, teacher: PersonInterface, student: DummyInterface):
  30. if not isinstance(teacher, PersonInterface):
  31. raise Exception("teacherがPersonInterfaceではありません")
  32. if not isinstance(student, DummyInterface):
  33. raise Exception("studentがPersonInterfaceではありません")
  34. self.teacher = teacher
  35. self.student = student
  36. def start(self):
  37. self.teacher.stand_up()
  38. self.student.stand_up()
  39. def inject_config(binder):
  40. binder.bind(PersonInterface, Teacher())
  41. binder.bind(DummyInterface, Student())
  42. def main():
  43. #teacher = Teacher()
  44. #student = Student()
  45. inject.configure(inject_config)
  46. con = TyoureiController()
  47. con.start()
  48. if __name__ == '__main__':
  49. main()

ようするにstudentのinterfaceをPersonInterfaceからDummyInterfaceに変更した。
これが良いのか悪いのかはちょっと微妙。
同じインターフェースだけど違うクラスを指定したときはエラーというのはDIの原則とかでエラーなのか、pythonのプログラムとしてただできないだけの問題なのかがわからない。

Page 38 of 69.

前のページ 次のページ



[添付ファイル]


お問い合わせ

プロフィール

すぺぺぺ

自己紹介

本サイトの作成者。
プログラムは趣味と勉強を兼ねて、のんびり本サイトを作っています。
フレームワークはdjango。
ChatGPTで自動プログラム作成に取り組み中。

サイト/ブログ

https://www.osumoi-stdio.com/novel/

ツイッター

@darkimpact0626