Consider the following example. The example is contrived but illustrates the point in a runnable example:
class MultiplicatorMixin: def multiply(self, m: int) -> int: return self.value * m class AdditionMixin: def add(self, b: int) -> int: return self.value + b class MyClass(MultiplicatorMixin, AdditionMixin): def __init__(self, value: int) -> None: self.value = value instance = MyClass(10) print(instance.add(2)) print(instance.multiply(2))
When executed this will give the following output:
12 20
The code works.
But running mypy
on it, yields the following errors:
example.py:4: error: "MultiplicatorMixin" has no attribute "value" example.py:10: error: "AdditionMixin" has no attribute "value"
I understand why mypy gives this result. But the mixin classes are never used by themselves. They are always used as additional superclasses.
For context, this is a pattern which has been used in an existing application and I am in the process of adding type-hints. And in this case, the errors are false-positives. I am thinking about rewriting the part using the mixins as I don't particularly like it and the same could probably be done with reorganising the class hierarchy.
But I still would like to know how something like this could be properly hinted.
In object-oriented programming languages, a mixin (or mix-in) is a class that contains methods for use by other classes without having to be the parent class of those other classes.
Type hints help you build and maintain a cleaner architecture. The act of writing type hints forces you to think about the types in your program. While the dynamic nature of Python is one of its great assets, being conscious about relying on duck typing, overloaded methods, or multiple return types is a good thing.
A mixin is a class such that some method of the class uses a method which is not defined in the class. Therefore the class is not meant to be instantiated, but rather serve as a base class. Otherwise the instance would have methods that cannot be called without raising an exception.
Introduction to Type Hints As the code base gets larger, type hints can help to debug and prevent some dumb mistakes. If you're using an IDE like PyCharm, you'll get a warning message whenever you've used the wrong data type, provided you're using type hints.
For reference, mypy recommends to implement mixins through a Protocol
(documentation here).
It works with mypy >= 750.
from typing import Protocol class HasValueProtocol(Protocol): @property def value(self) -> int: ... class MultiplicationMixin: def multiply(self: HasValueProtocol, m: int) -> int: return self.value * m class AdditionMixin: def add(self: HasValueProtocol, b: int) -> int: return self.value + b class MyClass(MultiplicationMixin, AdditionMixin): def __init__(self, value: int) -> None: self.value = value
The Protocol
base class is provided in the typing_extensions
package for Python 2.7 and 3.4-3.7.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With