概要
ABCMeta を使って Python のインタフェースに触れてみました
環境
- macOS 11.3.1
- Python 3.8.7
抽象クラスの作成
まずは ABCMeta を使って基底抽象クラスを作成してみます
@abstractmethod
を付与することで実装先でそのメソッドがないとエラーになります
from abc import ABCMeta, abstractmethod
class UserInterface(metaclass=ABCMeta):
def __init__(self, name="hawk", age=10):
self.name = name
self.age = age
@abstractmethod
def show_profile(self):
pass
使う
UserInterface を使って User クラスを定義します
先程説明したとおり @abstractmethod
を使っているので show_profile
がないと「TypeError: Can’t instantiate abstract class User with abstract methods show_profile」というエラーになります
from abc import ABCMeta, abstractmethod
class UserInterface(metaclass=ABCMeta):
def __init__(self, name="hawk", age=10):
self.name = name
self.age = age
@abstractmethod
def show_profile(self):
pass
class User(UserInterface):
def __init__(self):
super().__init__()
def show_profile(self):
print(self.name)
print(self.age)
user = User()
user.show_profile()
返り値として指定する
メソッドの返り値として Interface を指定することもできます
受け取り側は UserInterface の仕様を見てコールするべきメソッドなどを判断できます
from abc import ABCMeta, abstractmethod
class UserInterface(metaclass=ABCMeta):
def __init__(self, name="hawk", age=10):
self.name = name
self.age = age
self.scope = "default"
@abstractmethod
def show_profile(self):
pass
class User(UserInterface):
def __init__(self):
super().__init__()
def show_profile(self):
print(self.name)
print(self.age)
print(self.scope)
class AdminUser(UserInterface):
def __init__(self):
super().__init__()
self.scope = "all"
def show_profile(self):
print(self.name)
print(self.age)
print(self.scope)
user = User()
user.show_profile()
class UserFactory():
def create_user(self, name, age) -> UserInterface:
user = User()
if name == "admin":
user = AdminUser()
user.name = name
user.age = age
return user
factory = UserFactory()
user = factory.create_user("snowlog", 20)
user.show_profile()
print(user.__class__) # => <class '__main__.User'>
user = factory.create_user("admin", 30)
user.show_profile()
print(user.__class__) # => <class '__main__.AdminUser'>
classmethod + abstractmethod
classmethod も抽象メソッドとしてインタフェースに定義できます
実装クラス側でも @classmethod を定義して実装してあげます
from abc import ABCMeta, abstractmethod
class UserInterface(metaclass=ABCMeta):
def __init__(self, name="hawk", age=10):
self.name = name
self.age = age
self.scope = "default"
@abstractmethod
def show_profile(self):
pass
@classmethod
@abstractmethod
def hello(cls):
pass
class User(UserInterface):
def __init__(self):
super().__init__()
def show_profile(self):
print(self.name)
print(self.age)
print(self.scope)
@classmethod
def hello(cls):
print("Having a general user role.")
User.hello()
property + abstractmethod
@property を使うとアクセサが Ruby っぽくなります
これも抽象メソッドとして定義できます
setter も抽象メソッドとしてインタフェースに定義はしているものの実装していなくてもエラーにならないようです
from abc import ABCMeta, abstractmethod
class UserInterface(metaclass=ABCMeta):
def __init__(self, name="hawk", age=10):
self.name = name
self.age = age
self.scope = "default"
self._mail_address = ""
@abstractmethod
def show_profile(self):
pass
@property
@abstractmethod
def mail_address(self):
pass
@mail_address.setter
@abstractmethod
def mail_address(self, mail_address):
pass
class User(UserInterface):
def __init__(self):
super().__init__()
def show_profile(self):
print(self.name)
print(self.age)
print(self.scope)
print(self._mail_address)
@property
def mail_address(self):
return self._mail_address
@mail_address.setter
def mail_address(self, mail_address):
self._mail_address = mail_address
user = User()
user.mail_address = "user01@mail.domain"
print(user.mail_address)
0 件のコメント:
コメントを投稿