Domanda

Ho il seguente programma Python 2.6 e la definizione YAML (utilizzando PyYAML ):

import yaml

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

         """
    )

print type(x)
print x


Che si traduce nella seguente output:
<type 'dict'>
{'product': {'sku': 123, 'name': 'Product X', 'features': [{'weight': '10kg', 'size': '10x30cm'}]}}

E 'possibile creare un oggetto con i campi da x?

Vorrei il seguente:

print x.features[0].size

Sono consapevole che è possibile creare e l'istanza da una classe esistente, ma non è questo quello che voglio per questo scenario particolare.

Modifica

  • Aggiornata la parte confusa circa un 'oggetto fortemente tipizzato'.
  • accesso Cambiato in features a un indicizzatore come suggerito Alex Martelli
È stato utile?

Soluzione

In modo da avere un dizionario con chiavi stringa e valori che possono essere numeri, dizionari nidificati, elenchi, e vuoi per avvolgere che in un'istanza che consente di utilizzare attribuire l'accesso al posto di dict indicizzazione, e "call con un indice" al posto di lista indicizzazione - non so cosa 'fortemente tipizzato' ha a che fare con questo, o perché si pensa .features(0) è meglio di .features[0], ma, certo, è (un modo più naturale per indicizzare una lista!) fattibile. Ad esempio, un approccio semplice potrebbe essere:

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

Quindi x = wrap(x['product']) dovrebbe dare il vostro desiderio (il motivo per cui si desidera saltare quel livello quando la logica complessiva richiederebbe ovviamente x.product.features(0).size, non ho idea, ma è chiaro che saltare di meglio applicata al punto di chiamata, piuttosto che hard-coded nel classe wrapper o la funzione wrapper fabbrica che ho appena mostrato).

Modifica : come l'OP dice di voler features[0] piuttosto che features(0), basta cambiare le ultime due righe a

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

cioè., Definire __getitem__ (il metodo magico sottostante indicizzazione) anziché __call__ (il metodo magico sottostante esempio di guardia).

L'alternativa a "una classe esistente" (qui, Fourie) sarebbe quello di creare una nuova classe al volo sulla base di introspezione del dict avvolto - fattibile, anche, ma sul serio grigio scuro, se non addirittura nero , la magia, e senza alcun reale vantaggio operativa che mi viene in mente.

Se l'OP può chiarire esattamente il motivo per cui egli può essere brama dopo i picchi di meta-programmazione di creazione di classi al volo, che vantaggio crede potrebbe essere sempre in quel modo, ecc, vi mostrerò come farlo (e , probabilmente, farò anche mostri il perché l'agognato-per il vantaggio sarà non , infatti, essere lì ;-). Ma la semplicità è una qualità importante in qualsiasi sforzo di programmazione, e l'utilizzo di "magia nera profondo" quando pianura, codice semplice come le opere di cui sopra bene, non è generalmente la migliore delle idee -!)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top