Abstract class and interface definitions
Project description
Abstract class and interface definitions.
Create an abstract.Abstraction
An Abstraction is a metaclass for defining abstract classes.
Let’s define an abstract AFoo class and give it an abstract do_foo method.
Like any python class, an Abstraction can have any name, but it may be helpful to distinguish abstract classes from others by prefixing their name with A.
>>> import abc
>>> import abstracts
>>> class AFoo(metaclass=abstracts.Abstraction):
...
... @abc.abstractmethod
... def do_foo(self):
... raise NotImplementedError
Abstract classes cannot be instantiated directly.
>>> AFoo()
Traceback (most recent call last):
...
TypeError: Can't instantiate abstract class AFoo with abstract method... do_foo
Create an implementer for an abstract.Abstraction
In order to make use of AFoo, we need to create an implementer for it.
>>> @abstracts.implementer(AFoo)
... class Foo:
... pass
The implementer must implement all of the abstract methods, defined by its abstract classes.
>>> Foo()
Traceback (most recent call last):
...
TypeError: Can't instantiate abstract class Foo with abstract method... do_foo
>>> @abstracts.implementer(AFoo)
... class Foo2:
...
... def do_foo(self):
... return "DID FOO"
>>> Foo2()
<__main__.Foo2 object at ...>
An implementer inherits from its Abstractions
An implementer class is a subclass of its Abstraction.
>>> issubclass(Foo2, AFoo)
True
Likewise an instance of an implementer is an instance of its Abstraction
>>> isinstance(Foo2(), AFoo)
True
The Abstraction class can be seen in the class bases, and the methods of the Abstraction can be invoked by the implementer.
>>> import inspect
>>> AFoo in inspect.getmro(Foo2)
True
Create an implementer that implements multiple Abstraction s.
An implementer can implement multiple abstractions.
Let’s create a second abstraction.
>>> class ABar(metaclass=abstracts.Abstraction):
...
... @abc.abstractmethod
... def do_bar(self):
... raise NotImplementedError
And now we can create an implementer that implememts both the AFoo and ABar Abstraction s.
>>> @abstracts.implementer((AFoo, ABar))
... class FooBar:
...
... def do_foo(self):
... return "DID FOO"
...
... def do_bar(self):
... return "DID BAR"
>>> FooBar()
<__main__.FooBar object at ...>
Defining abstract properties
Properties can be defined in an abstract class, and just like with normal methods, they must be implemented by any implementers.
>>> class AMover(metaclass=abstracts.Abstraction):
...
... @property
... @abc.abstractmethod
... def speed(self):
... return 5
...
... @property
... @abc.abstractmethod
... def direction(self):
... return "forwards"
Calling super() on an abstractmethod
Just like with pythons “Abstract Base Classes” you can call super() in an abstractmethod, to invoke an abstract implementation.
>>> @abstracts.implementer(AMover)
... class Mover:
...
... @property
... def direction(self):
... return "backwards"
...
... @property
... def speed(self):
... return super().speed
This custom implementation of AMover must implement both speed and direction, even if its implementation invokes the abstract implementation.
In this case it uses the default/abstract implementation of speed while providing its own implementation of direction.
>>> mover = Mover()
>>> mover
<__main__.Mover object at ...>
>>> mover.speed
5
>>> mover.direction
'backwards'
Defining an abstracts.Interface class
An Interface is much like an Abstraction, but with a few differences.
An Interface can only define methods with the @interfacemethod decorator.
It cannot define normal methods or methods with the @abstractmethod, only methods with @interfacemethod.
An @interfacemethod if invoked will always raise an NotImplementedError, and therefore cannot be used as an abstract implementation.
Lets add an Interface class that we can use.
In the way that it may be helpful to distinguish an Abstraction from other types of classes, it may be also useful to distinguish an Interface by using an I prefix when naming them.
>>> class IGeared(metaclass=abstracts.Interface):
...
... @property
... @abstracts.interfacemethod
... def number_of_gears(self):
... # Raising an error is ~superfluous as the decorator will raise
... # anyway if the method is invoked.
... raise NotImplementedError
Implementing an Interface
Just like with an Abstraction, an Interface can be implemented using the @implementer decorator.
An implementer, can implement a combination of Abstractions and Interfaces.
>>> @abstracts.implementer((AMover, IGeared))
... class Bicycle:
...
... @property
... def direction(self):
... return super().direction
...
... @property
... def speed(self):
... return super().speed
...
... @property
... def number_of_gears(self):
... return 7
>>> Bicycle().number_of_gears
7
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
File details
Details for the file abstracts-0.0.6-py3-none-any.whl
.
File metadata
- Download URL: abstracts-0.0.6-py3-none-any.whl
- Upload date:
- Size: 109.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.4 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.62.1 CPython/3.9.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7b71f775e5a37f65e52adfa2c154b95f80ec7861a879f457a452117c937e8693 |
|
MD5 | fe98c556add3c989899e43e9118888e3 |
|
BLAKE2b-256 | 501ec0aab99fc3192662455380cb439212d55ba5c770a96ef2d9048727f34979 |