【问题标题】:PyYAML parse into arbitary objectPyYAML 解析成任意对象
【发布时间】:2011-01-27 10:16:06
【问题描述】:

我有以下 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 的访问权限更改为索引器

【问题讨论】:

    标签: python yaml pyyaml


    【解决方案1】:

    所以你有一个包含字符串键和值的字典,可以是数字、嵌套字典、列表,并且你想将它包装到一个实例中,这样你就可以使用属性访问来代替 dict 索引,并且“调用一个索引”代替列表索引——不确定“强类型”与此有什么关系,或者为什么您认为 .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)的替代方案是基于内省包装的 dict 动态创建一个新类 - 也是可行的,但如果不是真的是深灰色的话

    em>黑色,魔法,没有任何我能想到的真正的运营优势。

    如果 OP 能够准确地阐明为什么他可能会渴望在动态创建类的元编程高峰之后,他认为他可能会获得什么优势,等等,我将展示如何做到这一点(以及,也许,我还会说明为什么渴望的优势实际上会存在;-)。但是在任何编程工作中,简单性都是一个重要的品质,当像上面这样简单、直接的代码工作得很好时,使用“深奥的魔法”通常不是最好的主意!-)

    【讨论】:

    • @Alex,感谢您的回答。抱歉,我在功能上弄乱了索引器,你说得对,它应该是 .features[0]。我正在更新我的帖子以避免进一步混淆。
    • 只需覆盖 __getitem__ 而不是 __call__ -- 让我进行编辑以显示这一点。
    • 这将完美运行。作为 Python 的新手,我不知道魔法方法,多么棒的概念!希望我能在以后动态创建课程时挑选你的大脑。我的问题的绝妙解决方案。
    猜你喜欢
    • 2016-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-28
    • 2021-05-17
    • 1970-01-01
    • 2012-12-06
    相关资源
    最近更新 更多