スポンサーリンク
概要
pythonでDIでオブジェクトを注入する方法に関するメモ。
スポンサーリンク
環境
python 3.7.6
スポンサーリンク
背景
pythonにはC#やJavaにあるようなインターフェースが存在しないため、コンストラクタからインタフェースを渡してのDIが不可能。
代わりに抽象クラスの仕組みを利用する事で実現が可能。
方法
オブジェクト
まずは下記のようなPersonクラスを定義する。
単純な値を保持するクラスである。
1 2 3 4 5 6 7 8 9 |
class Person: def __init__(self, id:str, name:str, age:int): self.id = id self.name = name self.age = age def __repr__(self): return f'[id:{self.id}, name:{self.name}, age:{self.age}]' |
このPersonクラスを取得できるようなクラスを抽象化して定義する。
実現方法
pythonには組み込みの機能としてabc(Abstract Base Class)といったものが提供されている。
このクラスを継承して抽象化したいメソッドに対して、abstractmethodをアノテーションとして付与する。
下記では、Personを全件返すfindAllメソッドを定義している。
1 2 3 4 5 6 7 8 |
from abc import ABCMeta, abstractmethod from typing import List class AbstractPersonRepository(metaclass=ABCMeta): @abstractmethod def findAll(self) -> List[Person]: pass |
この抽象クラスを継承して、メソッドを実装することで実現が可能。
1 2 3 4 5 6 7 8 |
class InMemoryPersonRepository(AbstractPersonRepository): def findAll(self) -> List[Person]: persons = [ Person("1", "Python太郎", 10), Person("2", "Python花子", 15) ] return persons |
あとは、こんな感じで抽象化された処理を引数として受け取るクラスを定義して使用する。
1 2 3 4 5 6 7 |
class PersonService: def __init__(self, repository:AbstractPersonRepository): self.__repository = repository def findAll(self) -> List[Person]: return self.__repository.findAll() |
1 2 3 |
service = PersonService(InMemoryPersonRepository()) persons = service.findAll() print("persons:{}".format(repr(persons))) |