How to write class inheritance in Python? I will write a practical edition about. There is no basic edition.
It seems to be useful when creating software and large-scale libraries. If you write a method that is defined in the same way in multiple classes in an abstract class or a parent class that serves as a template, you do not need to define it in a child class.
This time, let's take scikit-learn's TransformerMixin
, which everyone loves, as an example. TransformerMixin
is a class used everywhere in scikit-learn. In scikit-learn, fit
and transform
are often used for preprocessing etc., and fit_transform
that performs them together is implemented in Transformer Mixin
.
This mechanism makes fit_transform
available just by inheriting, which is a very simple example.
For reference, python usually implements an abstract class that inherits from ʻabc.ABCMeta`. There is a package called abc that is always available in Python, and it is used to define abstract classes. See also the references at the end of this article.
I tried the following two points. I will write.
Let's read the code below first. Quoted from scikit-learn's github page. scikit-learn TransformerMixin
base.py
...
class TransformerMixin:
def fit_transform(self, X, y=None, **fit_params):
...
if y is None:
...
return self.fit(X, **fit_params).transform(X)
else:
...
return self.fit(X, y, **fit_params).transform(X)
...
When defining an abstract class in Python, a class called ʻabc.ABCMeta is often used. However, in the above example, only the method is defined without using ʻabc.ABCMeta
.
ʻAbstract classes that use abc.ABCMeta and
@ abc.abstractmethod can be inherited to create classes that force implementation. On the other hand, with TransformerMixin above, we just want to make common methods available to all inheritance destinations. In this case, you don't have to use ʻabc
.
I will try writing. If you use an abstract class that uses ʻabc`, it works as follows. In addition, please do not worry because the function name etc. is Abekobe ...
$ cat sampleAbsclass.py
from abc import ABCMeta, abstractmethod
class DensityMixin(metaclass=ABCMeta):
@abstractmethod
def score(self, X, y=None):
pass
class OneClassSvm(DensityMixin):
def __init__(self):
print('echo echo', 'hello hello')
# def score(self, X, y=None):
# print(*X.shape)
def main():
ocsvm = OneClassSvm()
from numpy.random import randn
X=randn(100, 10)
ocsvm.score(X)
return 0
if __name__=='__main__':
main()
$ python sampleAbsclass.py
Traceback (most recent call last):
File "sampleAbsclass.py", line 21, in <module>
main()
File "sampleAbsclass.py", line 14, in main
ocsvm = OneClassSvm()
TypeError: Can't instantiate abstract class OneClassSvm with abstract methods score
There is a method score
with a @ abstractmethod
decorator in the DensityMixin
of the abstract class, but it is not implemented in the inherited ʻOneClassSvm` ** Keshikaran! The error message is **.
If you uncomment the score function of ʻOneClassSvm`, it works as below.
$ python sampleAbsclass.py
echo echo hello hello
100 10
Another caveat that comes up when you make heavy use of ʻabc.ABCMeta is when class A inherits multiple abstract classes. "If even one class A has an abstract class that inherits ʻabc.ABCMeta
, then the other inherited classes must also inherit ʻabc.ABCMeta`."
There is a point. If you break this, you will get the following error message.
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
This is the same phenomenon in other languages, so I think it's convenient to do so. You should learn the theory of programming languages properly ...
There is an implementation of scikit-learn that uses ʻabc.ABCMeta, so let's take a look there as well. The following is quoted from [_PLS --scikit-learn](https://github.com/scikit-learn/scikit-learn/blob/1495f69242646d239d89a5713982946b8ffcf9d9/sklearn/cross_decomposition/pls_.py#L120). You can see that
@abstractmethod is added only to the
init` method.
pls_.py
from abc import ABCMeta, abstractmethod
...
class _PLS(BaseEstimator, TransformerMixin, RegressorMixin, MultiOutputMixin,
metaclass=ABCMeta):
...
@abstractmethod
def __init__(self, n_components=2, scale=True, deflation_mode="regression",
mode="A", algorithm="nipals", norm_y_weights=False,
max_iter=500, tol=1e-06, copy=True):
...
def fit(self, X, Y):
...
def transform(self, X, Y=None, copy=True):
...
def predict(self, X, copy=True):
...
def fit_transform(self, X, y=None):
...
def _more_tags(self):
return {'poor_score': True}
Other classes inherit this _PLS class, but ABCMeta comes out only at this time. The _PLS class itself inherits only Mixins, and from the first example, it does not have any inheritance from the ABCMeta class.
So, ʻabc.ABCMeta` will be used again ** if there is a method that must be implemented in multiple classes, it will be inherited in the abstract class **.
(It's a mystery to redefine fit_transform
in _PLS
even though it inherits TransformerMixin
.)
In this article, starting from the implementation example of TransformerMixin
of scikit-learn, I briefly summarized how to create a class to organize common parts.
It is a common practice to inherit the ʻabc.ABCMeta class to make it an abstract class, but if you just want to have one or two methods in common for multiple classes, use ʻabc.ABCMeta
. I confirmed that it seems unlikely.
It's silly to repeat the same implementation over and over, so make good use of class inheritance.
How to use ʻabc.ABCMeta` is introduced in the following article.
-I tried various things with the abstract class of Python --Qiita -How to create an abstract class in Python !!
Recommended Posts