keys - Una clase de python que actúa como dict
python dictionary of dictionaries (5)
Quiero escribir una clase personalizada que se comporte como dict
, así que heredo de dict
.
Mi pregunta, sin embargo, es: ¿Necesito crear un miembro privado de dict
en mi __init__()
?. No veo el sentido de esto, ya que ya tengo el comportamiento dict
si simplemente heredo de dict
.
¿Alguien puede señalar por qué la mayoría de los fragmentos de herencia se ven como el siguiente?
class CustomDictOne(dict):
def __init__(self):
self._mydict = {}
# other methods follow
En lugar de lo más simple ...
class CustomDictTwo(dict):
def __init__(self):
# initialize my other stuff here ...
# other methods follow
En realidad, creo que sospecho que la respuesta a la pregunta es para que los usuarios no puedan acceder directamente a su diccionario (es decir, tienen que usar los métodos de acceso que ha proporcionado).
Sin embargo, ¿qué pasa con el operador de acceso a la matriz []
? ¿Cómo podría uno implementar eso? Hasta ahora, no he visto un ejemplo que muestre cómo anular el operador []
.
Entonces, si una función de acceso []
no se proporciona en la clase personalizada, ¿los métodos base heredados operarán en un diccionario diferente?
Probé el siguiente fragmento para probar mi comprensión de la herencia de Python:
class myDict(dict):
def __init__(self):
self._dict = {}
def add(self, id, val):
self._dict[id] = val
md = myDict()
md.add(''id'', 123)
print md[id]
Tuve el siguiente error:
KeyError: <identificador de función incorporada>
¿Qué está mal con el código de arriba?
¿Cómo corrijo la clase myDict
para poder escribir código así?
md = myDict()
md[''id''] = 123
[Editar]
He editado el código de la muestra anterior para deshacerme del error tonto que hice antes de salir corriendo de mi escritorio. Fue un error tipográfico (debería haberlo detectado en el mensaje de error).
Consulte la documentación sobre cómo emular tipos de contenedores . En su caso, el primer parámetro para add
debe ser self
.
El problema con este pedazo de código:
class myDict(dict):
def __init__(self):
self._dict = {}
def add(id, val):
self._dict[id] = val
md = myDict()
md.add(''id'', 123)
... es que su método ''agregar'' (... y cualquier método que quiera ser miembro de una clase) debe tener un ''yo'' explícito declarado como su primer argumento, como:
def add(self, ''id'', 23):
Para implementar la sobrecarga del operador para acceder a los elementos por clave, busque en los docs los métodos mágicos __getitem__
y __setitem__
.
Tenga en cuenta que debido a que Python usa Duck Typing, en realidad puede no haber ninguna razón para derivar su clase dict personalizada de la clase dict del lenguaje, sin saber más acerca de lo que está tratando de hacer (por ejemplo, si necesita pasar una instancia de este isinstance(MyDict(), dict) == True
en algún código en algún lugar que se rompa a menos que sea isinstance(MyDict(), dict) == True
), es mejor que solo implemente la API que hace que su clase sea lo suficientemente similar a un dictado y se detenga allí.
En aras de la exhaustividad, aquí está el enlace a la documentación mencionada por @ björn-pollex para la última versión de Python 2.x (2.7.7 en el momento de la redacción):
(Perdón por no usar la función de comentarios, no estoy autorizado a hacerlo por .)
Me gusta esto
class CustomDictOne(dict):
def __init__(self,*arg,**kw):
super(CustomDictOne, self).__init__(*arg, **kw)
Ahora puede usar las funciones incorporadas, como dict.get()
como self.get()
.
No necesita envolver un self._dict
oculto self._dict
. Tu clase ya es un dict.
class Mapping(dict):
def __setitem__(self, key, item):
self.__dict__[key] = item
def __getitem__(self, key):
return self.__dict__[key]
def __repr__(self):
return repr(self.__dict__)
def __len__(self):
return len(self.__dict__)
def __delitem__(self, key):
del self.__dict__[key]
def clear(self):
return self.__dict__.clear()
def copy(self):
return self.__dict__.copy()
def has_key(self, k):
return k in self.__dict__
def update(self, *args, **kwargs):
return self.__dict__.update(*args, **kwargs)
def keys(self):
return self.__dict__.keys()
def values(self):
return self.__dict__.values()
def items(self):
return self.__dict__.items()
def pop(self, *args):
return self.__dict__.pop(*args)
def __cmp__(self, dict_):
return self.__cmp__(self.__dict__, dict_)
def __contains__(self, item):
return item in self.__dict__
def __iter__(self):
return iter(self.__dict__)
def __unicode__(self):
return unicode(repr(self.__dict__))
o = Mapping()
o.foo = "bar"
o[''lumberjack''] = ''foo''
o.update({''a'': ''b''}, c=44)
print ''lumberjack'' in o
print o
In [187]: run mapping.py
True
{''a'': ''b'', ''lumberjack'': ''foo'', ''foo'': ''bar'', ''c'': 44}