2012-02-06 16 views
7

Il titolo è abbastanza auto-esplicativo.Come posso aggiungere una tupla python a un file YAML usando pyYAML?

Dopo aver salvato una tupla in un file YAML, ho qualcosa che assomiglia a questo:

ambient: !!python/tuple [0.3, 0.3 ,0.3] 

Quando provo a caricarlo con yaml.safe_load (oggetto_file), continuo a ricevere un errore che legge :

yaml.constructor.ConstructorError: could not determine a constructor for the tag 'tag:yaml.org,2002:python/tuple' 

Che cosa deve essere fatto?

risposta

9

In pyyaml, SafeLoader non include un caricatore per i tipi nativi python, solo i tipi definiti nella specifica yaml. È possibile visualizzare i tipi di SafeLoader e Loader qui nell'esempio di interazione riportato di seguito.

È possibile definire una nuova classe Loader che aggiunge nella tupla pitone, ma non altri tipi, quindi dovrebbe essere ancora abbastanza sicuro:

import yaml 

class PrettySafeLoader(yaml.SafeLoader): 
    def construct_python_tuple(self, node): 
     return tuple(self.construct_sequence(node)) 

PrettySafeLoader.add_constructor(
    u'tag:yaml.org,2002:python/tuple', 
    PrettySafeLoader.construct_python_tuple) 

doc = yaml.dump(tuple("foo bar baaz".split())) 
print repr(doc) 
thing = yaml.load(doc, Loader=PrettySafeLoader) 
print thing 

conseguente:

'!!python/tuple [foo, bar, baaz]\n' 
('foo', 'bar', 'baaz') 

Vedi sotto per i costruttori associati alle classi SafeLoader e Loader.

>>> yaml.SafeLoader.yaml_constructors 
{None: <unbound method SafeConstructor.construct_undefined>, 
u'tag:yaml.org,2002:binary': <unbound method SafeConstructor.construct_yaml_binary>, 
u'tag:yaml.org,2002:bool': <unbound method SafeConstructor.construct_yaml_bool>, 
u'tag:yaml.org,2002:float': <unbound method SafeConstructor.construct_yaml_float>, 
u'tag:yaml.org,2002:int': <unbound method SafeConstructor.construct_yaml_int>, 
u'tag:yaml.org,2002:map': <unbound method SafeConstructor.construct_yaml_map>, 
u'tag:yaml.org,2002:null': <unbound method SafeConstructor.construct_yaml_null>, 
u'tag:yaml.org,2002:omap': <unbound method SafeConstructor.construct_yaml_omap>, 
u'tag:yaml.org,2002:pairs': <unbound method SafeConstructor.construct_yaml_pairs>, 
u'tag:yaml.org,2002:seq': <unbound method SafeConstructor.construct_yaml_seq>, 
u'tag:yaml.org,2002:set': <unbound method SafeConstructor.construct_yaml_set>, 
u'tag:yaml.org,2002:str': <unbound method SafeConstructor.construct_yaml_str>, 
u'tag:yaml.org,2002:timestamp': <unbound method SafeConstructor.construct_yaml_timestamp>} 

>>> yaml.Loader.yaml_constructors 
{None: <unbound method SafeConstructor.construct_undefined>, 
u'tag:yaml.org,2002:binary': <unbound method SafeConstructor.construct_yaml_binary>, 
u'tag:yaml.org,2002:bool': <unbound method SafeConstructor.construct_yaml_bool>, 
u'tag:yaml.org,2002:float': <unbound method SafeConstructor.construct_yaml_float>, 
u'tag:yaml.org,2002:int': <unbound method SafeConstructor.construct_yaml_int>, 
u'tag:yaml.org,2002:map': <unbound method SafeConstructor.construct_yaml_map>, 
u'tag:yaml.org,2002:null': <unbound method SafeConstructor.construct_yaml_null>, 
u'tag:yaml.org,2002:omap': <unbound method SafeConstructor.construct_yaml_omap>, 
u'tag:yaml.org,2002:pairs': <unbound method SafeConstructor.construct_yaml_pairs>, 
u'tag:yaml.org,2002:python/bool': <unbound method Constructor.construct_yaml_bool>, 
u'tag:yaml.org,2002:python/complex': <unbound method Constructor.construct_python_complex>, 
u'tag:yaml.org,2002:python/dict': <unbound method Constructor.construct_yaml_map>, 
u'tag:yaml.org,2002:python/float': <unbound method Constructor.construct_yaml_float>, 
u'tag:yaml.org,2002:python/int': <unbound method Constructor.construct_yaml_int>, 
u'tag:yaml.org,2002:python/list': <unbound method Constructor.construct_yaml_seq>, 
u'tag:yaml.org,2002:python/long': <unbound method Constructor.construct_python_long>, 
u'tag:yaml.org,2002:python/none': <unbound method Constructor.construct_yaml_null>, 
u'tag:yaml.org,2002:python/str': <unbound method Constructor.construct_python_str>, 
u'tag:yaml.org,2002:python/tuple': <unbound method Constructor.construct_python_tuple>, 
u'tag:yaml.org,2002:python/unicode': <unbound method Constructor.construct_python_unicode>, 
u'tag:yaml.org,2002:seq': <unbound method SafeConstructor.construct_yaml_seq>, 
u'tag:yaml.org,2002:set': <unbound method SafeConstructor.construct_yaml_set>, 
u'tag:yaml.org,2002:str': <unbound method SafeConstructor.construct_yaml_str>, 
u'tag:yaml.org,2002:timestamp': <unbound method SafeConstructor.construct_yaml_timestamp>} 
+0

Questo ha perfettamente senso. Grazie mille! – blz

0

Almeno secondo the PyYAML documentation:

La funzione limiti yaml.safe_load questa capacità di semplici oggetti Python come numeri interi o elenchi.

La lista, as you can see in the source, è un po 'più ampio, ma non include tag:yaml.org,2002:python/tuple.

Sembra che se si genera un tipo !!python/tuple nel file YAML, si utilizza dump() anziché safe_dump(). Se questo è il caso, probabilmente dovresti passare a utilizzare load() al posto di safe_load(), poiché i file creati da dump() non possono essere caricati da safe_load(). (Vedi lo description of safe_dump()).

+1

ho aggiunto la parola mancante * non *, ma non sono sicuro se non hai in realtà vuole formularla viceversa ... –

+0

@NiklasB .: Grazie. – ig0774

+0

In quali condizioni una persona ragionevole considererebbe pericoloso l'uso di yaml.loader (al contrario di safe_loader)? Sto scrivendo un gioco che carica le risorse definite in un file YAML. Un download dannoso potrebbe presumibilmente sovrascrivere i miei file YAML, quindi il mio gioco caricherà un codice pericoloso, ma questo sembra essere un problema per l'utente finale. Non c'è molto che posso fare ... giusto? – blz

Problemi correlati