Pregunta

Tengo el siguiente programa Python 2.6 y definición YAML (usando PyYAML ):

import yaml

x = yaml.load(
    """
        product:
           name     : 'Product X'
           sku      : 123
           features :
             - size    :  '10x30cm'
               weight  :  '10kg'

         """
    )

print type(x)
print x


Lo que resulta en la siguiente salida:
<type 'dict'>
{'product': {'sku': 123, 'name': 'Product X', 'features': [{'weight': '10kg', 'size': '10x30cm'}]}}

Es posible crear un objeto con campos de x?

Me gustaría a lo siguiente:

print x.features[0].size

Soy consciente de que es posible crear e instancia de una clase existente, pero eso no es lo que quiero para este escenario particular.

Editar

  • Se ha actualizado la parte confusa acerca de un 'objeto fuertemente tipado'.
  • Acceso a features cambiado a un controlador paso a paso como se sugiere Alex Martelli
¿Fue útil?

Solución

Así que tienes un diccionario con claves de cadena y valores que pueden ser números, diccionarios, listas anidadas, y desea que envuelva en una instancia que le permite utilizar atributos de acceso en lugar de indexación dict, y "llamar con un índice" en lugar de la lista de indexación - no sé qué 'inflexible' tiene que ver con esto, o por qué cree que .features(0) es mejor que .features[0], pero, claro, que es (tal manera más natural para indexar una lista!) factible. Por ejemplo, un enfoque sencillo podría ser:

def wrap(datum):
  # don't wrap strings
  if isinstance(datum, basestring):
    return datum
  # don't wrap numbers, either
  try: return datum + 0
  except TypeError: pass
  return Fourie(datum)

class Fourie(object):
  def __init__(self, data):
    self._data = data
  def __getattr__(self, n):
    return wrap(self._data[n])
  def __call__(self, n):
    return wrap(self._data[n])

Así x = wrap(x['product']) debe darle su deseo (¿por qué desea omitir ese nivel cuando su lógica global, obviamente, requieren x.product.features(0).size, no tengo ni idea, pero es evidente que la omisión de una mejor aplicación en el punto de escala en lugar de no modificable en el clase de contenedor o la función de fábrica envoltorio que acabo de muestra).

Editar : como dice el OP sí quiere features[0] en lugar de features(0), basta con cambiar las dos últimas líneas a

  def __getitem__(self, n):
    return wrap(self._data[n])

es decir., Definir __getitem__ (el método magia indexación subyacente) en lugar de __call__ (el método magia subyacente ejemplo-llamada).

La alternativa a "una clase existente" (en este caso, Fourie) sería la creación de una nueva clase sobre la marcha basado en la introspección de la dict envuelto - factible, también, pero en serio de color gris oscuro, si no realmente negro , la magia, y sin ninguna ventaja operativa real que se me ocurre.

Si el PO puede aclarar exactamente por qué puede ser anhelando los picos de los meta-programación de la creación de clases sobre la marcha, lo que él cree que la ventaja pudo conseguir de esa manera, etc, voy a mostrar cómo hacerlo (y , probablemente, yo también voy a mostrar por qué el ansiado-para la ventaja será no en el hecho de estar allí ;-). Pero la simplicidad es una cualidad importante en cualquier empresa de programación, y el uso de "profunda magia negra" cuando llano, código sencillo como lo anterior funciona muy bien, por lo general no es la mejor de las ideas -)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top