¿Cómo puedo agregar una tupla de python a un archivo YAML usando pyYAML?

El título es bastante autoexplicativo.

Cuando guardo una tupla en un archivo YAML, obtengo algo que se parece a esto:

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

Cuando bash cargarlo con yaml.safe_load (file_object), sigo recibiendo un error que dice:

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

¿Lo que hay que hacer?

En pyyaml, SafeLoader no incluye un cargador para los tipos nativos de python, solo los tipos definidos en la especificación de yaml. Puede ver los tipos de SafeLoader y Loader aquí en el ejemplo de interacción a continuación.

Puede definir una nueva clase de cargador que agregue en la tupla de Python, pero no en otros tipos, por lo que aún debería ser bastante seguro:

 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 

Resultando en:

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

Vea a continuación los constructores asociados con las clases SafeLoader y Loader.

 >>> yaml.SafeLoader.yaml_constructors {None: , u'tag:yaml.org,2002:binary': , u'tag:yaml.org,2002:bool': , u'tag:yaml.org,2002:float': , u'tag:yaml.org,2002:int': , u'tag:yaml.org,2002:map': , u'tag:yaml.org,2002:null': , u'tag:yaml.org,2002:omap': , u'tag:yaml.org,2002:pairs': , u'tag:yaml.org,2002:seq': , u'tag:yaml.org,2002:set': , u'tag:yaml.org,2002:str': , u'tag:yaml.org,2002:timestamp': } >>> yaml.Loader.yaml_constructors {None: , u'tag:yaml.org,2002:binary': , u'tag:yaml.org,2002:bool': , u'tag:yaml.org,2002:float': , u'tag:yaml.org,2002:int': , u'tag:yaml.org,2002:map': , u'tag:yaml.org,2002:null': , u'tag:yaml.org,2002:omap': , u'tag:yaml.org,2002:pairs': , u'tag:yaml.org,2002:python/bool': , u'tag:yaml.org,2002:python/complex': , u'tag:yaml.org,2002:python/dict': , u'tag:yaml.org,2002:python/float': , u'tag:yaml.org,2002:python/int': , u'tag:yaml.org,2002:python/list': , u'tag:yaml.org,2002:python/long': , u'tag:yaml.org,2002:python/none': , u'tag:yaml.org,2002:python/str': , u'tag:yaml.org,2002:python/tuple': , u'tag:yaml.org,2002:python/unicode': , u'tag:yaml.org,2002:seq': , u'tag:yaml.org,2002:set': , u'tag:yaml.org,2002:str': , u'tag:yaml.org,2002:timestamp': } 

Al menos según la documentación de PyYAML :

La función yaml.safe_load limita esta capacidad a objetos de Python simples como enteros o listas.

La lista, como se puede ver en la fuente , es algo más extensa pero no incluye la tag:yaml.org,2002:python/tuple .

Parece que si está generando un tipo !!python/tuple en su archivo YAML, está utilizando dump() en lugar de safe_dump() . Si ese es el caso, probablemente deberías usar load() en lugar de safe_load() , ya que los archivos creados por dump() no están garantizados para ser safe_load() por safe_load() . (Ver la descripción de safe_dump() ).