abc — 抽象基类
优质
小牛编辑
138浏览
2023-12-01
How ABCs Work
# abc_base.py
import abc
class PluginBase(metaclass=abc.ABCMeta):
@abc.abstractmethod
def load(self, input):
"""Retrieve data from the input source
and return an object.
"""
@abc.abstractmethod
def save(self, output, data):
"""Save the data object to the output."""
Registering a Concrete Class
# abc_register.py
import abc
from abc_base import PluginBase
class LocalBaseClass:
pass
@PluginBase.register
class RegisteredImplementation(LocalBaseClass):
def load(self, input):
return input.read()
def save(self, output, data):
return output.write(data)
if __name__ == '__main__':
print('Subclass:', issubclass(RegisteredImplementation,
PluginBase))
print('Instance:', isinstance(RegisteredImplementation(),
PluginBase))
Implementation Through Subclassing
# abc_subclass.py
import abc
from abc_base import PluginBase
class SubclassImplementation(PluginBase):
def load(self, input):
return input.read()
def save(self, output, data):
return output.write(data)
if __name__ == '__main__':
print('Subclass:', issubclass(SubclassImplementation,
PluginBase))
print('Instance:', isinstance(SubclassImplementation(),
PluginBase))
# abc_find_subclasses.py
import abc
from abc_base import PluginBase
import abc_subclass
import abc_register
for sc in PluginBase.__subclasses__():
print(sc.__name__)
Helper Base Class
# abc_abc_base.py
import abc
class PluginBase(abc.ABC):
@abc.abstractmethod
def load(self, input):
"""Retrieve data from the input source
and return an object.
"""
@abc.abstractmethod
def save(self, output, data):
"""Save the data object to the output."""
class SubclassImplementation(PluginBase):
def load(self, input):
return input.read()
def save(self, output, data):
return output.write(data)
if __name__ == '__main__':
print('Subclass:', issubclass(SubclassImplementation,
PluginBase))
print('Instance:', isinstance(SubclassImplementation(),
PluginBase))
Incomplete Implementations
# abc_incomplete.py
import abc
from abc_base import PluginBase
@PluginBase.register
class IncompleteImplementation(PluginBase):
def save(self, output, data):
return output.write(data)
if __name__ == '__main__':
print('Subclass:', issubclass(IncompleteImplementation,
PluginBase))
print('Instance:', isinstance(IncompleteImplementation(),
PluginBase))
Concrete Methods in ABCs
# abc_concrete_method.py
import abc
import io
class ABCWithConcreteImplementation(abc.ABC):
@abc.abstractmethod
def retrieve_values(self, input):
print('base class reading data')
return input.read()
class ConcreteOverride(ABCWithConcreteImplementation):
def retrieve_values(self, input):
base_data = super(ConcreteOverride,
self).retrieve_values(input)
print('subclass sorting data')
response = sorted(base_data.splitlines())
return response
input = io.StringIO("""line one
line two
line three
""")
reader = ConcreteOverride()
print(reader.retrieve_values(input))
print()
Abstract Properties
# abc_abstractproperty.py
import abc
class Base(abc.ABC):
@property
@abc.abstractmethod
def value(self):
return 'Should never reach here'
@property
@abc.abstractmethod
def constant(self):
return 'Should never reach here'
class Implementation(Base):
@property
def value(self):
return 'concrete property'
constant = 'set by a class attribute'
try:
b = Base()
print('Base.value:', b.value)
except Exception as err:
print('ERROR:', str(err))
i = Implementation()
print('Implementation.value :', i.value)
print('Implementation.constant:', i.constant)
# abc_abstractproperty_rw.py
import abc
class Base(abc.ABC):
@property
@abc.abstractmethod
def value(self):
return 'Should never reach here'
@value.setter
@abc.abstractmethod
def value(self, new_value):
return
class PartialImplementation(Base):
@property
def value(self):
return 'Read-only'
class Implementation(Base):
_value = 'Default value'
@property
def value(self):
return self._value
@value.setter
def value(self, new_value):
self._value = new_value
try:
b = Base()
print('Base.value:', b.value)
except Exception as err:
print('ERROR:', str(err))
p = PartialImplementation()
print('PartialImplementation.value:', p.value)
try:
p.value = 'Alteration'
print('PartialImplementation.value:', p.value)
except Exception as err:
print('ERROR:', str(err))
i = Implementation()
print('Implementation.value:', i.value)
i.value = 'New value'
print('Changed value:', i.value)
Abstract Class and Static Methods
# abc_class_static.py
import abc
class Base(abc.ABC):
@classmethod
@abc.abstractmethod
def factory(cls, *args):
return cls()
@staticmethod
@abc.abstractmethod
def const_behavior():
return 'Should never reach here'
class Implementation(Base):
def do_something(self):
pass
@classmethod
def factory(cls, *args):
obj = cls(*args)
obj.do_something()
return obj
@staticmethod
def const_behavior():
return 'Static behavior differs'
try:
o = Base.factory()
print('Base.value:', o.const_behavior())
except Exception as err:
print('ERROR:', str(err))
i = Implementation.factory()
print('Implementation.const_behavior :', i.const_behavior())