2008-10-22 8 views
25

he empezado a utilizar construcciones como éstas:notación de puntos de estilo Javascript para las teclas del diccionario unpythonic?

class DictObj(object): 
    def __init__(self): 
     self.d = {} 
    def __getattr__(self, m): 
     return self.d.get(m, None) 
    def __setattr__(self, m, v): 
     super.__setattr__(self, m, v) 

Actualización: basado en este hilo, he revisó la aplicación DictObj a:

class dotdict(dict): 
    def __getattr__(self, attr): 
     return self.get(attr, None) 
    __setattr__= dict.__setitem__ 
    __delattr__= dict.__delitem__ 

class AutoEnum(object): 
    def __init__(self): 
     self.counter = 0 
     self.d = {} 
    def __getattr__(self, c): 
     if c not in self.d: 
      self.d[c] = self.counter 
      self.counter += 1   
     return self.d[c] 

donde DictObj es un diccionario que puede ser acceder a través de la notación de puntos:

d = DictObj() 
d.something = 'one' 

me resulta estéticamente más agradable que d['something']. Tenga en cuenta que acceder a una clave indefinida devuelve None en lugar de generar una excepción, lo que también es agradable.

Actualización: Smashery hace un buen punto, que mhawke se expande para una solución más fácil. Me pregunto si hay efectos secundarios indeseables de usar dict en lugar de definir un nuevo diccionario; si no, me gusta mucho la solución de mhawke.

AutoEnum es una enumeración de incremento automático, que se utiliza como esto:

CMD = AutoEnum() 

cmds = { 
    "peek": CMD.PEEK, 
    "look": CMD.PEEK, 
    "help": CMD.HELP, 
    "poke": CMD.POKE, 
    "modify": CMD.POKE, 
} 

Ambos están trabajando bien para mí, pero me siento unpythonic sobre ellos.

¿Son estas construcciones realmente malas?

+0

¡Muy bonito! el dotdict de clase es mínimo y elegante. Creo que lo usaré Sin embargo, sobre el "AutoEnum" ... mi problema es que el "valor" para cada "clave" puede ser diferente en cada ejecución, por lo que no puede usarlo para valores almacenados en una base de datos o nada (bueno, Supongo que podría mantener los valores iguales, si tiene cuidado de no cambiar nunca el orden de acceso inicial ... pero los valores no son explícitos) –

+3

¡Espera !, hay un problema con el puntoDiccionario: no funciona si lo intenta usar una clave que es el nombre de un método dict, como cualquiera de estos: "elementos", "claves", "obtener", "borrar", "copiar", etc. ... eso es un problema. ¿Hay alguna forma de evitar esto? ¿Hay alguna forma de "tener tu pastel y comértelo también"? (para poder llamar a los métodos dict, pero también para poder usar claves como "elementos" y "borrar" sin cambiar la sintaxis?). –

Respuesta

8

Esta es una versión más simple de la clase DictObj:

class DictObj(object): 
    def __getattr__(self, attr): 
     return self.__dict__.get(attr) 

>>> d = DictObj() 
>>> d.something = 'one' 
>>> print d.something 
one 
>>> print d.somethingelse 
None 
>>> 
+0

¿Algún efecto secundario posible al usar __dict__? Si no, me gusta. – Parand

+0

Si no recuerdo mal, __dict__ no es técnicamente parte de la especificación de Python. Es decir, otras VM no necesitan implementar. También recuerdo que todas las VM actuales (IronPython, Jython, PyPy) en realidad * do * usan un __dict__ para diccionarios de objetos. – Ryan

+0

Esto es malo, me gusta la clase 'dotdict' de la pregunta * mucho * mejor. El 'dotdict' es un diccionario real, por lo que se puede convertir a JSON naturalmente, mientras que este objeto suyo no lo es. – hasen

3

Hasta donde yo sé, las clases de Python usan diccionarios para almacenar sus atributos de todos modos (eso está oculto para el programador), así que me parece que lo que has hecho allí es emular efectivamente una clase de Python ... usando un clase de pitón.

1

Me gusta la notación de puntos mucho mejor que los campos de diccionario personalmente. La razón es que hace que el autocompletado funcione mucho mejor.

12

Con respecto a DictObj, ¿funcionaría lo siguiente para usted? Una clase en blanco le permitirá agregar arbitrariamente o reemplazar cosas en un objeto contenedor.

class Container(object): 
    pass 

>>> myContainer = Container() 
>>> myContainer.spam = "in a can" 
>>> myContainer.eggs = "in a shell" 

Si desea no lanzar una AttributeError cuando no hay ningún atributo, ¿qué piensa usted acerca de lo siguiente? Personalmente, preferiría usar un dict para mayor claridad, o para usar una cláusula try/except.

class QuietContainer(object): 
    def __getattr__(self, attribute): 
     try: 
      return object.__getattr__(self,attribute) 
     except AttributeError: 
      return None 

>>> cont = QuietContainer() 
>>> print cont.me 
None 

Derecho?

+0

Acepto que crear una clase parece una forma mucho más limpia de manejar lo que está intentando. – monkut

+0

La diferencia clave es que no quiero lanzar una excepción cuando la clave no se ha definido previamente. – Parand

+0

¿Qué parte del ejemplo de Kevin arroja una excepción? –

1

No está mal si sirve a su propósito. "La practicidad supera a la pureza".

vi ese enfoque elserwhere (por ejemplo, en Paver), por lo que esto puede considerarse necesidad común (o deseo).

22

Su ejemplo de DictObj es realmente bastante común. El acceso a la notación de puntos de estilo de objeto puede ser una ganancia si se trata de "cosas que se parecen a objetos", es decir. tienen nombres de propiedades fijos que contienen solo caracteres válidos en identificadores de Python.Cosas como filas de bases de datos o envíos de formularios se pueden almacenar de forma útil en este tipo de objetos, lo que hace que el código sea un poco más legible sin el exceso de ['acceso a elementos'].

La implementación es un poco limitada: no se obtiene la buena sintaxis de compilador de dict, len(), comparaciones, 'in', iteración o buenos informes. Por supuesto, puede poner en práctica esas cosas por uno mismo, pero en el mundo nuevo estilo de clases se puede obtener de forma gratuita con sólo la subclasificación dict:

class AttrDict(dict): 
    __getattr__ = dict.__getitem__ 
    __setattr__ = dict.__setitem__ 
    __delattr__ = dict.__delitem__ 

para obtener el comportamiento-default-Ninguno, simplemente subclase Python 2.5 's collections.defaultdict class en lugar de dict.

+0

He intentado esto con defaultdict, pero todavía no es volver Ninguno de underfined:

 >>> d = AttrDict() >>> d.me Traceback (most recent call last): File "", line 1, in  KeyError: 'me' 
Parand

+0

que se establecieron en una versión ligeramente modificada de este, ahora incluido en la pregunta anterior actualizada. – Parand

+0

defaultdict funcionó para mí: ¿recordó incluir la función de fábrica en el constructor? es decir. d = defaultdict (lambda: ninguno). Si olvida ese bit defaultict solo funciona como un dict normal. También puede anular __init__ en AttrDict para hacerlo automáticamente, tal vez. – bobince

2

El principal inconveniente de utilizar algo así como su DictObj es que o bien tienen que limitar teclas permitidas o no se puede tener en sus métodos DictObj como .keys(), .values(), .items(), etc.

3

No es "incorrecto "para hacer esto, y puede ser más agradable si los diccionarios tienen una gran posibilidad de convertirse en objetos en algún momento, pero ten cuidado de las razones para tener acceso a soporte en el primer lugar:

  1. acceso Dot pueden' t utilizar palabras clave como claves.
  2. El acceso a puntos tiene que utilizar caracteres con identificador de Python en las claves.
  3. Los diccionarios pueden contener cualquier elemento hashable, no solo cadenas.

También tenga en cuenta que siempre puede hacer que sus objetos accedan como diccionarios si decide cambiar a objetos más adelante.

Para un caso como este me gustaría por defecto al mantra "legibilidad cuenta": presumiblemente otros programadores de Python leerán su código y probablemente no estarán esperando híbridos de diccionario/objeto en todas partes. Si es una buena decisión de diseño para una situación en particular, úsala, pero no la usaría sin necesidad de hacerlo.

0

Debido a que usted pide efectos secundarios indeseables:

Una desventaja es que en los editores visuales como Eclipse + PyDev, verá muchos errores variables no definidas en las líneas que utilizan la notación de punto. Pydef no podrá encontrar tales definiciones de "objetos" de tiempo de ejecución. Mientras que en el caso de un diccionario normal, sabe que acaba de obtener una entrada de diccionario.

Tendría que 1) ignorar esos errores y vivir con cruces rojas; 2) suprima esas advertencias línea por línea usando # @ Variable no definida o 3) deshabilite el error variable indefinido por completo, haciendo que pierda las definiciones de variables reales no definidas.

2

Hay una simetría entre this y this respuesta:

class dotdict(dict): 
    __getattr__= dict.__getitem__ 
    __setattr__= dict.__setitem__ 
    __delattr__= dict.__delitem__ 

La misma interfaz, simplemente implementadas al revés ...

class container(object): 
    __getitem__ = object.__getattribute__ 
    __setitem__ = object.__setattr__ 
    __delitem__ = object.__delattr__ 
1

No te vistas Bunch.

Es un elemento secundario del diccionario y puede importar YAML o JSON, o convertir cualquier diccionario existente en un grupo y viceversa. Una vez que "agrupe", un diccionario gana notaciones de punto sin perder ningún otro método de diccionario.

+0

montón se retiró y el reemplazo de ir ahora es ** masque ** (https://pypi.python.org/pypi/munch). Utilice 'Munch()' en lugar de 'Bunch()' y 'munchify' en lugar de' bunchify' – Dannid

Cuestiones relacionadas