PyYAML解析为任意对象

Phi*_*rie 5 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
Run Code Online (Sandbox Code Playgroud)


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

可以使用来自x?的字段创建对象?

我想要以下内容:

print x.features[0].size
Run Code Online (Sandbox Code Playgroud)

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

编辑:

  • 更新了关于"强类型对象"的混乱部分.
  • features根据Alex Martelli的建议改变了对索引器的访问权限

Ale*_*lli 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])
Run Code Online (Sandbox Code Playgroud)

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

编辑:因为OP说他确实想要features[0]而不是features(0),只需将最后两行更改为

  def __getitem__(self, n):
    return wrap(self._data[n])
Run Code Online (Sandbox Code Playgroud)

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

"现有类"(此处Fourie)的替代方案是基于对包裹的词典进行内省而动态创建新类 - 也可行,但是严重的深灰色,如果不是实际上是黑色的,魔法,并且没有任何我能想到的真正的运营优势.

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