PyYAML解析为任意对象

时间:2010-03-14 16:58:20

标签: python yaml pyyaml

我有以下Python 2.6程序和YAML定义(使用PyYAML):

import yaml

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

         """
    )

print type(x)
print x


这导致以下输出:
<type 'dict'>
{'product': {'sku': 123, 'name': 'Product X', 'features': [{'weight': '10kg', 'size': '10x30cm'}]}}

可以使用x中的字段创建对象吗?

我想要以下内容:

print x.features[0].size

我知道可以从现有的类创建和实例,但这不是我想要的特定场景。

修改:

  • 更新了关于“强类型对象”的令人困惑的部分。
  • 根据建议Alex Martelli
  • features的访问权限更改为索引器

1 个答案:

答案 0 :(得分:8)

所以你有一个包含字符串键和值的字典,可以是数字,嵌套字典,列表,并且你想将它包装到一个实例中,它允许你使用属性访问来代替字典索引,并且“调用一个索引“代替列表索引 - 不确定什么”强类型“与此有关,或者为什么你认为.features(0)优于.features[0](这种更自然的方式来索引列表!),但是,当然,这是可行的。例如,一个简单的方法可能是:

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

所以x = wrap(x['product'])应该给你你的愿望(当你的整体逻辑显然需要x.product.features(0).size时,为什么你想跳过那个级别,我不知道,但很明显跳过更好地适用于在包装器类或我刚刚展示的包装器工厂函数中调用而不是硬编码。

修改:由于OP说他确实想要features[0]而非features(0),只需将最后两行更改为

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

即,定义__getitem__(基础索引的神奇方法)而不是__call__(实例调用的神奇方法)。

“现有类”(此处为Fourie)的替代方法是基于内省包裹的字典动态创建一个新类 - 可行,但是严重的深灰色,如果不是实际上黑色,魔术,没有我能想到的任何真正的操作优势。

如果OP能够明确地说明为什么他可能会在动态创建课程的元编程高峰之后渴望,他相信他可能会有这样的优势等等,我将展示如何做到(和,也许,我也会说明为什么渴望的优势将实际上存在;-)。但是简单性在任何编程工作中都是一个重要的品质,并且使用“深色魔法”时,如上所述的简单明了的代码工作得很好,通常不是最好的想法! - )