Question

Voici une double question, avec une partie théorique, et pratique:

Lors de la sous-classe, dict:

class ImageDB(dict):
    def __init__(self, directory):
        dict.__init__(self)  # Necessary?? 
        ...

devrait dict.__init__(self) être appelé, comme une mesure de «sécurité» (par exemple, au cas où il y a des détails de mise en œuvre non triviaux qui comptent)? y a-t-il un risque que le code se brise avec une future version de Python si dict.__init__() est ne pas appelé? Je cherche une raison fondamentale de faire une chose ou l'autre, ici (pratiquement, appeler dict.__init__() est sécurisé).

Je suppose que quand ImageDB.__init__(self, directory) s'appelle, Self est déjà un nouvel objet de dict vide, et qu'il n'est donc pas nécessaire d'appeler dict.__init__ (Je veux que le dict soit vide, au début). Est-ce correct?

Éditer:

La question la plus pratique derrière la question fondamentale ci-dessus est la suivante. Je pensais à la sous-classe dict parce que j'utiliserais assez souvent la syntaxe DB […] (au lieu de faire DB.Content […] tout le temps); Les seules données de l'objet (attribut) sont en effet vraiment un dict. Je souhaite ajouter quelques méthodes à la base de données (comme get_image_by_name(), ou get_image_by_code(), par exemple), et ne remplacer que le __init__(), parce que la base de données d'images est définie par le répertoire qui le contient.

En résumé, la question (pratique) pourrait être: quelle est une bonne implémentation pour quelque chose qui se comporte comme un dictionnaire, sauf que son initialisation est différente (elle ne prend qu'un nom de répertoire), et qu'il a des méthodes supplémentaires?

Les «usines» ont été mentionnées dans de nombreuses réponses. Donc je suppose __init__() et ajouter des méthodes, ou écrivez-vous une fonction (d'usine) qui renvoie un dict, à laquelle vous ajoutez des méthodes? Je suis enclin à préférer la première solution, car la fonction d'usine renvoie un objet dont le type n'indique pas qu'il a une sémantique et des méthodes supplémentaires, mais qu'en pensez-vous?

Modifier 2:

Je comprends de la réponse de tout le monde selon laquelle ce n'est pas une bonne idée de sous-classe le dict lorsque la nouvelle classe "n'est pas un dictionnaire", et en particulier quand c'est __init__ la méthode ne peut pas prendre les mêmes arguments que les dicts __init__ (ce qui est le cas dans la "question pratique" ci-dessus). En d'autres termes, si je comprends bien, le consensus semble être: lorsque vous sous-classez, toutes les méthodes (y compris l'initialisation) doivent avoir la même signature que les méthodes de classe de base. Cela permet d'Isinstance (Subclass_instance, dict) pour garantir que subclass_instance.__init__() peut être utilisé comme dict.__init__(), par exemple.

Une autre question pratique apparaît alors: comment une classe qui est comme un dict, à l'exception de sa méthode d'initialisation, doit-elle être mise en œuvre? sans sous-classe? Cela nécessiterait un code de passe-partout gênant, non?

Était-ce utile?

La solution

Tu devrais probablement appeler dict.__init__(self) lors de la sous-classe; En fait, vous ne savez pas ce qui se passe précisément dans le dict (car c'est un intégré), et cela pourrait varier d'une versions et des implémentations. Ne pas l'appeler peut entraîner un comportement inapproprié, car vous ne pouvez pas savoir où le dict détient ses structures de données internes.

Au fait, vous ne nous avez pas dit ce que vous vouloir faire; Si vous voulez un cours avec un comportement de dict (cartographie), et que vous n'avez pas vraiment besoin d'un dict (par exemple, il n'y a pas de code isinstance(x, dict) Partout dans votre logiciel, comme il se doit), vous feriez probablement mieux d'utiliser UserDict.UserDict ou UserDict.DictMixin Si vous êtes sur Python <= 2,5, ou collections.MutableMapping Si vous êtes sur Python> = 2.6. Ceux-ci fourniront à votre classe un excellent comportement de dict.

EDIT: J'ai lu dans un autre commentaire que vous ne déposez aucune de la méthode de Dict! Ensuite, il est inutile de sous-classement, ne le faites pas.

def createImageDb(directory):
    d = {}
    # do something to fill in the dict
    return d

Edit 2: Vous souhaitez hériter de Dict pour ajouter de nouvelles méthodes, mais vous n'avez pas besoin de remplacer aucun. Qu'un bon choix pourrait être:

class MyContainer(dict):
    def newmethod1(self, args):
        pass

    def newmethod2(self, args2):
        pass


def createImageDb(directory):
    d = MyContainer()
    # fill the container
    return d

Soit dit en passant: quelles méthodes ajoutez-vous? Êtes-vous sûr de créer une bonne abstraction? Peut-être que vous feriez mieux d'utiliser une classe qui définit les méthodes dont vous avez besoin et utilisez un dict "normal" en interne.

Func d'usine:http://en.wikipedia.org/wiki/factory_method_pattern

C'est simplement un moyen de déléguer la construction d'une instance à une fonction au lieu de remplacer / changer ses constructeurs.

Autres conseils

Vous devez généralement appeler le cours de base ' __init__ Alors pourquoi faire une exception ici?

Soit ne pas remplacer __init__ ou si vous avez besoin de remplacer __init__ classe de base d'appel __init__, Si vous vous inquiétez des arguments, il suffit de passer * args, ** kwargs ou rien si vous voulez un dict vide, par exemple

class MyDict(dict):
    def __init__(self, *args, **kwargs ):
        myparam = kwargs.pop('myparam', '')
        dict.__init__(self, *args, **kwargs )

Nous ne devons pas supposer ce que fait Baseclass ou ne pas faire, il est mal de ne pas appeler la classe de base __init__

Méfiez-vous du décapage lors de la sous-classe INDICT; Ceci, par exemple, a besoin de __getNewargs__ en 2.7, et peut-être __getstate__ __setstate__ dans les versions plus anciennes. (Je ne sais pas pourquoi.)

class Dotdict( dict ):
    """ d.key == d["key"] """

    def __init__(self, *args, **kwargs):
        dict.__init__( self, *args, **kwargs )
        self.__dict__ = self

    def __getnewargs__(self):  # for cPickle.dump( d, file, protocol=-1)
        return tuple(self)

PEP 372 traite de l'ajout d'un dict ordonné au module des collections.

Il prévient que "le dict de sous-classe est une tâche non triviale et de nombreuses implémentations ne remplacent pas correctement toutes les méthodes, ce qui peut conduire à des résultats inattendus".

Le proposé (et accepté) correctif à Python3.1 utilise un __init__ Cela ressemble à ceci:

+class OrderedDict(dict, MutableMapping):
+    def __init__(self, *args, **kwds):
+        if len(args) > 1:
+            raise TypeError('expected at most 1 arguments, got %d' % len(args))
+        if not hasattr(self, '_keys'):
+            self._keys = []
+        self.update(*args, **kwds)

Sur la base de cela, il ressemble à dict.__init__() n'a pas besoin d'être appelé.

Éditer: Si vous ne remplacez ni ne prolongez dictLes méthodes, donc, je suis d'accord avec Alan Franzoni: utilisez une usine de dict plutôt que la sous-classe:

def makeImageDB(*args,**kwargs):
   d = {}
   # modify d
   return d

Si vous prévoyez de sous-classer quelque chose comme dict type de base, vous pouvez également considérer le UserDict des collections. UserDict est conçu pour être sous-classé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top