Sous-classement dict: faut-dict.__init__() s'appelle?
Ici est une double question, avec une partie théorique et pratique:
Lorsque le sous-classement dict:
class ImageDB(dict):
def __init__(self, directory):
dict.__init__(self) # Necessary??
...
devrait dict.__init__(self)
être appelés, tout comme une "sécurité" mesurer (par exemple, dans le cas où il y a quelques non-trivial détails de l'implémentation de la matière)? il y a un risque que le code de rompre avec une future version de Python si dict.__init__()
est pas appelé? Je suis à la recherche d'une raison fondamentale de faire une chose ou l'autre, ici (dans la pratique, l'appel de dict.__init__()
est sûr).
Ma conjecture est que lorsque ImageDB.__init__(self, directory)
est appelé, en soi, est déjà un nouvel vide dict objet, et qu'il n'est donc pas nécessaire de faire appel dict.__init__
(je veux le dict vide, au premier abord). Est-ce correct?
Modifier:
Le plus pratique question derrière la question fondamentale ci-dessus est le suivant. Je pensais de sous-classement dict parce que je voudrais utiliser la db[...] la syntaxe assez souvent (au lieu de faire de la db.contenu[...] tout le temps); l'objet est seulement de données (attribut) est en effet vraiment un dict. Je veux ajouter quelques méthodes à la base de données (comme get_image_by_name()
, ou get_image_by_code()
, par exemple), et remplacez uniquement les __init__()
, parce que l'image de la base de données est défini par le répertoire qui le contient.
En résumé, l' (pratique) la question pourrait être: ce qui est une bonne mise en œuvre pour quelque chose qui se comporte comme un dictionnaire, sauf que son initialisation est différent (il suffit d'un nom de répertoire), et qu'il a d'autres méthodes?
"Usines" ont été mentionnés dans de nombreuses réponses. Donc je suppose que tout cela se résume à: ne vous sous-classe dict, remplacer __init__()
et ajouter des méthodes, ou écrivez-vous un (réglage d'usine) la fonction qui retourne un dict, à laquelle vous pouvez ajouter des méthodes? Je suis enclin à préférer la première solution, parce que l'usine de la fonction retourne un objet dont le type n'indique pas qu'il a une sémantique supplémentaire et des méthodes, mais qu'en pensez-vous?
Edit 2:
Je déduis de tout le monde de répondre que c'est pas une bonne idée de la sous-classe dict lorsque la nouvelle de la classe "n'est pas un dictionnaire", et en particulier lors de son __init__
méthode ne peut pas prendre les mêmes arguments que dict est __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-classe, toutes les méthodes (y compris l'initialisation) doit avoir la même signature que les méthodes de classe de base. Cela permet isinstance(subclass_instance, dict), afin de garantir que subclass_instance.__init__()
peut être utilisé comme dict.__init__()
, par exemple.
Une autre question d'ordre pratique s'ouvre alors: comment une classe qui est juste comme dict, à l'exception de sa méthode d'initialisation, être mis en œuvre? sans sous-classement? cela aurait besoin d'un peu gênant code réutilisable, non?
- Une usine de la fonction est le chemin à parcourir. Si vous avez besoin de personnaliser instance de comportement, alors vous voudrez peut-être créer une sous-classe. Si vous voulez juste pour remplacer l'initialisation, vous n'avez pas besoin de sous-classement quoi que ce soit, parce que votre cas ne sont pas différents de la norme, celles. Rappelez-vous que init n'est pas considéré comme faisant partie de l'interface de l'instance, mais de la classe.
- Aussi loin que je le vois pour ce problème, il serait préférable d'ajouter les
__getitem__
méthode à votre ImageDB au lieu de sous-classement d'un dict, parce que ce n'est pas un dict. Cela permet de faire ce que vous voulez, sans avoir toutes ces méthodes commepop()
qui semblent être inapproprié pour votre classe. - Bon point, à propos de la pop, c'est en effet, pour le moment du moins, hors de propos (le contenu de base de données est définie lors de l'initialisation seulement). Je pense que c'est bien meilleur que la mise en œuvre étroitement adapter les fonctionnalités nécessaires.
Vous devez vous connecter pour publier un commentaire.
Vous devriez probablement appel
dict.__init__(self)
lorsque le sous-classement; en fait, vous ne savez pas ce qui se passe précisément dans le dict (puisque c'est un builtin), et qui peuvent varier selon les versions et les mises en œuvre. Pas d'appel, il peut entraîner un mauvais comportement, puisque vous ne pouvez pas savoir où dict est tenue de ses structures de données internes.Par la manière, vous ne nous dites pas ce que vous voulez à faire; si vous souhaitez une classe avec des dict (mapping) des comportements, et vous n'avez pas vraiment besoin d'une dict (par exemple, il n'y a pas de code à faire
isinstance(x, dict)
n'importe où dans votre logiciel, comme elle doit l'être), vous êtes probablement mieux à l'aide deUserDict.UserDict
ouUserDict.DictMixin
si vous êtes sur python <= 2.5, oucollections.MutableMapping
si vous êtes sur python >= 2.6 . Ces fournira à votre classe avec un excellent dict comportement.EDIT: j'ai lu dans un autre commentaire que vous n'êtes pas ignorant tous des dict de la méthode! Ensuite, il n'y a aucun point dans le sous-classement, ne pas le faire.
EDIT 2: vous souhaitez hériter du dict ajouter de nouvelles méthodes, mais vous n'avez pas besoin de remplacer tout. Un bon choix peut être fait:
Par la route: quels sont les moyens de vous ajouter? Êtes-vous sûr que vous êtes en train de créer une bonne abstraction? Peut-être que vous feriez mieux d'utiliser une classe qui définit les méthodes que vous avez besoin et de l'utilisation "normale" dict en interne pour cela.
Usine func:
http://en.wikipedia.org/wiki/Factory_method_pattern
C'est simplement une façon de déléguer la construction d'une occurrence à une fonction au lieu de l'annulation/modification de ses constructeurs.
__init__
(j'ai détaillé ce dans une version récente de la question), mais rien d'autre...Vous devriez généralement appel de la classe de base
__init__
alors, pourquoi faire une exception ici?Ne pas remplacer
__init__
ou si vous avez besoin de remplacer__init__
appel de la classe de base__init__
, Si vous vous inquiétez au sujet des arguments que l'on vient passer *args, **kwargs ou rien si vous souhaitez vide dict par exempleNous ne devrions pas supposer que baseclass est en train de faire ou ne pas faire, c'est mal de ne pas l'appel de la classe de base
__init__
__init__
est en effet ce que je suis en train de faire. Depuis qu'il ressemble à l'appeler avec aucun argument ne fait rien, je suis juste curieux au sujet de faits essentiels à propos de Python qui permette de ne pas être appelé!dict.__init__(self)
(n'ayant pas d'autres arguments) n'existe pas (comme "il ne fera jamais rien").super(MyDict, self).__init__(…)
.Méfiez-vous de décapage lorsque le sous-classement dict; ceci par exemple des besoins __getnewargs__ en 2.7,
et peut-être __getstate__ __setstate__ dans les anciennes versions. (Je n'ai aucune idée pourquoi.)
PEP 372 traite de l'ajout d'un ordre dict pour les collections module.
Il avertit que "sous-classement dict est une tâche non triviale et de nombreuses implémentations ne pas remplacer toutes les méthodes correctement, ce qui peut conduire à des résultats inattendus."
Le projet (et accepté) patch pour python3.1 utilise un
__init__
qui ressemble à ceci:Sur cette base, il ressemble à
dict.__init__()
n'a pas besoin d'être appelé.Edit: Si vous n'êtes pas de la substitution ou l'extension de toute de
dict
's méthodes, alors, je suis d'accord avec Alan Franzoni: utiliser un dict usine plutôt que de sous-classement:dict.__init__()
avec Python 3.1 est sûr, mais pour l'avenir? Depuis que je ne pas surcharger une méthode, dans ImageDB, sous-classement est très sûr; seulement l'initialisation est spécial (il construit le dict).Si vous prévoyez de la sous-classe quelque chose comme
dict
type de base vous pouvez également envisager de laUserDict
de collections.UserDict
est conçu pour être sous-classé.UserDict
était principalement intéressante avant de Python 2.2 lorsque vous ne pouviez pas sous-classedict
.