0
votes

Python: hiérarchie des classes abstraites sans méthodes abstraites

Donc, voici un problème:

  1. Je veux définir une classe abstraite, disons abstractha , qui ne nécessite pas de sous-classes pour mettre en œuvre de ses méthodes, mais plutôt pour étendre ses fonctionnalités. En termes de java qui serait une classe d'interface.

  2. De plus, je veux être capable de créer une sous-classe abstraite, disons abstractb , du abstractta avec les mêmes propriétés, mais quelques méthodes redéfinir ou Extension des méthodes de classe de base.

    Je ne veux pas cependant faire la classe ( abstractha ) abstrait E.g. via la vérification du nom de la classe dans __ init __ ou __ nouveau __ , car cela nécessiterait une sous-classe abstraite ( abstractb ) pour redéfinir cette méthode avec sa fonctionnalité principale, c'est-à-dire la construction ou l'initialisation d'une nouvelle instance. Ou appeler super () .__ init __ (...) que je préférerais éviter également (peut-être que je me trompe ici).

    Alors, je veux quelque chose Comme ça: xxx

    ci-dessous j'ai une solution possible. Y a-t-il des inconvénients que je néglige-t-il? Meilleure solution?

    merci!


2 commentaires

Devrait Class Ax (Abstractha): Pass Soyez légal? Quel serait le point de refusement instanciation directe de abstractha mais permettant l'instanciation de hache ?


@cheppner, bonne question. Je dois accepter que cette exigence soit plus une préférence que la nécessité. La raison pour laquelle je veux avoir une classe abstraite est que l'instanciation de cette classe mère ne fait aucun sens. Comme si dans la mise en œuvre d'animaux virtuels, il n'a pas de sens d'instancier des animaux ou des mammifères. Au lieu de cela, il faut instancier des espèces plus détaillées. Je tiens donc à rendre plus difficile à abuser de la classe uniquement à dessein de définir des propriétés communes. Quant à la partie du poing, il n'est pas assez difficile d'interdire complètement la mus mustueuse, mais suffisamment pour l'empêcher d'accident. Un peu comme _private_identifiers.


3 Réponses :


0
votes

Voici une solution possible:

class AbstractA:
    _is_abstract = True

    def __init__(self):
        if self._is_abstract:
            raise RuntimeError("Abstract class instantiation.")
        # do initialization stuff

    def __init_subclass__(self):   # is called every time class is subclassed
        self._is_abstract = False  # thus makes sure abstract check fails on a subclass

class AbstractMixin:
    def __init_subclass__(self):
        self._is_abstract = True

class AbstractB(AbstractMixin, AbstractA):  # AbstractMixin takes precendence on MRO,
    # inherit __init__                      # so the class abstract check returns True.

    def __init_subclass__(self):
        self._is_abstract = False

class A(AbstractA):
    pass

class B(AbstractB):
    pass

AbstractA()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.

AbstractB()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __init__
RuntimeError: Abstract class instantiation.

A()
<__main__.A object at 0x7f0bba5112e8>

B()
<__main__.B object at 0x7f0bba511438>


0 commentaires

0
votes
>>> B()
B
<__main__.B object at 0x7f8c816a58d0>
>>> 


1 commentaires

J'ai spécifiquement mentionné cette approche et pourquoi je ne veux pas l'utiliser dans une question.



0
votes

Dans Python, vous mettriez probablement en œuvre les classes de base "abstraites" comme mix-ins. Il n'y a rien de spécial que vous devez faire; Par convention, vous ajouteriez mixin code> au nom pour indiquer qu'il n'est pas censé être instancié directement, mais simplement utilisé comme classe de base pour d'autres classes.

class AMixin:
    def __init__(self):
        # do initialization stuff

    def very_common_method(self, ...):
        # do very common stuff

class BMixin(AMixin):
    # do not duplicate initialization stuff here, inherit instead

    def less_common_method(self, ...):
        # do less common stuff

class AX(AMixin):
    def specific_method_1(self, ...):

class BX(BMixin):
    def specific_method_2(self, ...):

class Foo:
    ...

class Bar(Foo, BMixin):
    ...


1 commentaires

mixin dans le nom n'indique pas qu'il devrait simplement être "utilisé comme une classe de base", cela doit plutôt l'indiquer, il doit être utilisé comme mixin, c'est-à-dire secondaire, tertiaire, etc. Parent, fournissant des morceau de fonctionnalité.