Comment écrire l'héritage de classe en Python? J'écrirai une édition pratique sur. Il n'y a pas d'édition de base.
Cela semble utile lors de la création de logiciels et de bibliothèques à grande échelle. Si vous écrivez une méthode qui est définie de la même manière dans plusieurs classes de la classe abstraite ou de la classe parente qui sert de modèle, vous n'avez pas besoin de la définir dans la classe enfant.
Cette fois, prenons comme exemple le TransformerMixin
de scikit-learn, que tout le monde adore. TransformerMixin
est une classe utilisée partout dans scikit-learn. Dans scikit-learn, «fit» et «transform» sont souvent utilisés pour le prétraitement, etc., et «fit_transform» qui les exécute ensemble est implémenté dans «Transformer Mixin».
Ce mécanisme est un exemple très simple que fit_transform
peut être utilisé simplement en héritant.
Pour référence, python implémente généralement une classe abstraite qui hérite de ʻabc.ABCMeta`. Il existe un package appelé abc qui est toujours disponible en Python et est utilisé pour définir des classes abstraites. Voir aussi les références à la fin de cet article.
J'ai essayé les deux points suivants. J'écrirai.
Lisons d'abord le code ci-dessous. Il est tiré de la page github de scikit-learn. 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)
...
Lors de la définition d'une classe abstraite en Python, une classe appelée ʻabc.ABCMeta est souvent utilisée. Cependant, dans l'exemple ci-dessus, seule la méthode est définie sans utiliser ʻabc.ABCMeta
.
«Les classes abstraites qui utilisent abc.ABCMeta» et «@ abc.abstractmethod» peuvent être héritées pour créer des classes qui forcent l'implémentation. D'un autre côté, avec TransformerMixin ci-dessus, nous voulons simplement rendre les méthodes communes disponibles pour toutes les destinations d'héritage. Dans ce cas, vous n'avez pas besoin d'utiliser ʻabc`.
J'essaierai d'écrire. Si vous utilisez une classe abstraite qui utilise ʻabc`, cela fonctionne comme suit. De plus, ne vous inquiétez pas car le nom de la fonction etc. est 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
Il existe une méthode score
avec un décorateur @ abstractmethod
dans le DensityMixin
de la classe abstraite, mais elle n'est pas implémentée dans le ʻOneClassSvm` ** Keshikaran hérité! Le message d'erreur est **.
Si vous décommentez la fonction de partition de ʻOneClassSvm`, cela fonctionne comme ci-dessous.
$ python sampleAbsclass.py
echo echo hello hello
100 10
Une autre mise en garde qui apparaît lorsque vous utilisez beaucoup ʻabc.ABCMeta est lorsque la classe A hérite de plusieurs classes abstraites. "Si même une classe A a une classe abstraite qui hérite de ʻabc.ABCMeta
, alors les autres classes héritées doivent également hériter de ʻabc.ABCMeta`."
Il y a un point. Si vous interrompez cela, vous recevrez le message d'erreur suivant.
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
Cela se produit également dans d'autres langues, donc je pense que c'est pratique de le faire. Vous devriez apprendre la théorie du langage de programmation correctement ...
Il existe une implémentation de scikit-learn qui utilise ʻabc.ABCMeta, alors jetons un œil là aussi. Ce qui suit est extrait de [_PLS --scikit-learn](https://github.com/scikit-learn/scikit-learn/blob/1495f69242646d239d89a5713982946b8ffcf9d9/sklearn/cross_decomposition/pls_.py#L120). Vous pouvez voir que
@ abstractmethod est ajouté uniquement à la méthode
__init __`.
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}
D'autres classes héritent de cette classe _PLS, mais ABCMeta ne sort que pour le moment. La classe _PLS elle-même n'hérite que de Mixin et, du premier exemple, elle n'a pas d'héritage de la classe ABCMeta.
Ainsi, ʻabc.ABCMeta` est utilisé à nouveau, mais ** s'il y a une méthode qui doit être implémentée dans plusieurs classes, elle sera héritée dans la classe abstraite **.
(C'est un mystère de redéfinir fit_transform
dans _PLS
même s'il hérite de TransformerMixin
.)
Dans cet article, à partir de l'exemple d'implémentation de TransformerMixin
de scikit-learn, nous avons brièvement résumé comment créer une classe pour organiser les parties communes.
C'est une pratique courante d'hériter de la classe ʻabc.ABCMeta pour en faire une classe abstraite, mais si vous voulez juste avoir une ou deux méthodes en commun pour plusieurs classes, utilisez ʻabc.ABCMeta
. J'ai confirmé que cela semble peu probable.
Il est ridicule de répéter la même implémentation encore et encore, alors faites bon usage de l'héritage de classe.
Comment utiliser ʻabc.ABCMeta` est présenté dans l'article suivant.
Recommended Posts