2012-02-06 127 views
7

標題不言自明。如何使用pyYAML將python元組添加到YAML文件中?

當我一個元組保存到YAML文件,我得到的東西看起來是這樣的:

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

當我試着使用yaml.safe_load(FILE_OBJECT)來加載它,我不斷收到讀取錯誤:

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

需要做什麼?

回答

9

在pyyaml中,SafeLoader不包含python本機類​​型的加載器,僅包含yaml規範中定義的類型。您可以在下面的交互示例中看到SafeLoaderLoader的類型。

您可以定義一個新的Loader類在Python元組增加了,而不是其他類型的,所以應該還是很安全:導致

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 

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

見下文用於與SafeLoader和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

這很有道理。非常感謝你! – blz 2012-02-07 12:07:32

0

至少根據the PyYAML documentation

功能yaml.safe_load限制這種能力像整數或列表簡單Python對象。

列表as you can see in the source比較廣泛,但不包括tag:yaml.org,2002:python/tuple

看來,如果您在YAML文件中生成!!python/tuple類型,那麼您使用的是dump()而不是safe_dump()。如果是這種情況,您應該切換到使用load()代替safe_load(),因爲由dump()創建的文件不能保證可由safe_load()加載。 (見description of safe_dump())。

+1

我添加缺少的詞*不*,但我不知道是否你實際上並沒有想要制定它倒過來... – 2012-02-07 00:44:25

+0

@NiklasB:謝謝。 – ig0774 2012-02-07 00:45:12

+0

在合理的人認爲使用yaml.loader(與safe_loader相反)的危險條件下,在什麼情況下?我正在編寫一個加載YAML文件中定義的資產的遊戲。惡意下載可能會覆蓋我的YAML文件,從而導致我的遊戲加載危險代碼,但這似乎是最終用戶的問題。我沒有太多的工作可以......對吧? – blz 2012-02-07 12:11:18