Mixinクラスのメソッドの中で、インスタンス変数にアクセスしたいとします。
例えば、インスタンス変数name
にアクセスするMixinクラスHelloMixin
を考えます。
class HelloMixin: def hello(self): return f"hello {self.name}"
HelloMixin
を継承した、MyClassWithHello
クラスを考えます。
class MyClassWithHello(HelloMixin): def __init__(self, name): self.name = name def use_hello(self): msg = self.hello() print(msg) my_class_with_hello = MyClassWithHello("Alice") my_class_with_hello.use_hello() # hello Alice
__init__
関数内でインスタンス変数name
を定義しています。
ここで、うっかりインスタンス変数name
の定義を忘れてしまったとします。
class HelloMixin: def hello(self): return f"hello {self.name}" class MyClassWithHello(HelloMixin): def __init__(self): pass def use_hello(self): msg = self.hello() print(msg) my_class_with_hello = MyClassWithHello() my_class_with_hello.use_hello() # AttributeError: 'MyClassWithHello' object has no attribute 'name'
use_hello
関数を実行すると、name
が見つからないよと怒られます。
というわけで、Mixinクラスを継承したクラスで、インスタンス変数の定義を強制したくなります。
どうしようか悩んでいたのですが、以下のような実装を思いつきました。
- Mixinクラス
HelloMixin
を抽象基底クラス(ABC)にする - Mixinクラス
HelloMixin
内で、@property
かつ@abstractmethod
でname
関数を定義する
from abc import ABC, abstractmethod class HelloMixin(ABC): @property @abstractmethod def name(self): pass def hello(self): return f"hello {self.name}" class MyClassWithHello(HelloMixin): def __init__(self, name): self.__name = name @property def name(self): return self.__name def use_hello(self): msg = self.hello() print(msg) my_class_with_hello = MyClassWithHello("Alice") my_class_with_hello.use_hello()
HelloMixin
内で@property
かつ@abstractmehod
でname
関数を定義しています。
そのため、継承先のMyClassWithHello
ではname
関数の実装が必須となります。
よって、Mixinクラスの継承先でインタンス変数の定義を強制することができました。
もしname
関数の実装を忘れると、オブジェクト作成時に以下のエラーを送出してくれます。
TypeError: Can't instantiate abstract class MyClassWithHello with abstract methods name
…というわけで、やりたいことは達成できたのですが、なんかボイラープレート感…