python subclass dictionary init

python - Subclasificación dict: ¿se debería llamar dict.__ init__()?



subclass dictionary (4)

Por lo general, debe llamar a la clase base '' __init__ ¿por qué hace una excepción aquí?

O bien no __init__ o si necesita cancelar __init__ call class class __init__ , si le preocupan los argumentos, simplemente pase * args, ** kwargs o nada si desea un dictado vacío, por ejemplo

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

No debemos asumir lo que hace o no hace baseclass, es incorrecto no llamar a la clase base __init__

Aquí hay una pregunta doble, con una parte teórica y una práctica:

Al subclasificar dict:

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

¿se debe dict.__init__(self) , solo como una medida de "seguridad" (por ejemplo, en caso de que haya algunos detalles de implementación no triviales que importen)? ¿Existe el riesgo de que el código se rompa con una versión futura de Python si no se llama dict.__init__() ? Estoy buscando una razón fundamental para hacer una cosa u otra, aquí (prácticamente, llamar a dict.__init__() es seguro).

Supongo que cuando se ImageDB.__init__(self, directory) , self ya es un nuevo objeto dict vacío, y que, por lo tanto, no hay necesidad de llamar a dict.__init__ (al dict.__init__ quiero que el dict esté vacío) . ¿Es esto correcto?

Editar :

La pregunta más práctica detrás de la pregunta fundamental anterior es la siguiente. Estaba pensando en hacer una subclase de dict porque usaría la sintaxis db [...] con bastante frecuencia (en lugar de hacer db.contents [...] todo el tiempo); el único dato (atributo) del objeto es realmente un dict. Quiero agregar algunos métodos a la base de datos (como get_image_by_name() , o get_image_by_code() , por ejemplo), y solo anular __init__() , porque la base de datos de imágenes está definida por el directorio que la contiene.

En resumen , la pregunta (práctica) podría ser: ¿qué es una buena implementación para algo que se comporta como un diccionario, excepto que su inicialización es diferente (solo toma un nombre de directorio), y que tiene métodos adicionales?

Las "fábricas" fueron mencionadas en muchas respuestas. Entonces supongo que todo se reduce a: ¿hace una subclase de dict, invalida __init__() y agrega métodos, o escribe una función (de fábrica) que devuelve un dict, a la que agrega métodos? Me inclino por preferir la primera solución, porque la función de fábrica devuelve un objeto cuyo tipo no indica que tenga métodos y semánticas adicionales, pero ¿qué piensa?

Edición 2 :

De la respuesta de todos, recojo que no es una buena idea subclasificar dict cuando la nueva clase "no es un diccionario", y en particular cuando su método __init__ no puede tomar los mismos argumentos que dict __init__ (lo cual es el caso en la práctica). pregunta "arriba). En otras palabras, si entiendo correctamente, el consenso parece ser: cuando se subclase, todos los métodos (incluida la inicialización) deben tener la misma firma que los métodos de la clase base. Esto permite que isinstance (subclass_instance, dict) garantice que subclass_instance.__init__() se puede usar como dict.__init__() , por ejemplo.

Luego surge otra pregunta práctica: ¿cómo debería implementarse una clase que es como dict, a excepción de su método de inicialización? sin subclasificar? Esto requeriría un código de repetitivo molesto, ¿no?


Probablemente debería llamar a dict.__init__(self) al crear subclases; de hecho, usted no sabe qué está sucediendo precisamente en dict (ya que está integrado), y eso puede variar entre las versiones e implementaciones. No llamarlo puede dar como resultado un comportamiento inadecuado, ya que no puede saber dónde está el dict que contiene sus estructuras de datos internas.

Por cierto, no nos dijiste lo que querías hacer; Si desea una clase con comportamiento de dict (mapeo), y realmente no necesita un dict (por ejemplo, no hay código haciendo isinstance(x, dict) en ninguna parte de su software, como debería ser), probablemente esté mejor. al usar UserDict.UserDict o UserDict.DictMixin si estás en python <= 2.5, o collections.MutableMapping si estás en python> = 2.6. Esos le proporcionarán a su clase un excelente comportamiento de dictado.

EDITAR: ¡Leí en otro comentario que no estás anulando ninguno de los métodos de dict! Entonces no hay ningún punto en subclasificar, no lo hagas.

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

EDIT 2: desea heredar de dict para agregar nuevos métodos, pero no necesita anular ninguno. Que una buena elección podría ser:

class MyContainer(dict): def newmethod1(self, args): pass def newmethod2(self, args2): pass def createImageDb(directory): d = MyContainer() # fill the container return d

Por cierto, ¿qué métodos estás agregando? ¿Estás seguro de que estás creando una buena abstracción? Tal vez sea mejor que use una clase que defina los métodos que necesita y use un dictador "normal" internamente.

Función de la fábrica: http://en.wikipedia.org/wiki/Factory_method_pattern

Es simplemente una forma de delegar la construcción de una instancia a una función en lugar de anular / cambiar sus constructores.


Tenga cuidado con el decapado al crear subclases dict; esto, por ejemplo, necesita __getnewargs__ en 2.7, y tal vez __getstate__ __setstate__ en versiones anteriores. (No tengo ni idea de porqué.)

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 trata de agregar un dictado ordenado al módulo de colecciones.

Advierte que "dictado de subclasificación es una tarea no trivial y muchas implementaciones no anulan todos los métodos correctamente, lo que puede dar lugar a resultados inesperados".

El patch propuesto (y aceptado) para python3.1 usa un __init__ que se ve así:

+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)

Basado en esto, parece que dict.__init__() no necesita ser llamado.

Edit: Si no está anulando o extendiendo ninguno de los métodos de dict , entonces estoy de acuerdo con Alan Franzoni: use una fábrica de dict en lugar de subclasificar:

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