PyYAML 解析为任意对象

发布于 2024-08-25 19:53:55 字数 852 浏览 9 评论 0原文

我有以下 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


这会产生以下输出:
<输入“字典”>
{'product': {'sku': 123, 'name': '产品 X', 'features': [{'weight': '10kg', 'size': '10x30cm'}]}}

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

我想要以下内容:

print x.features[0].size

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

编辑:

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

I have the following Python 2.6 program and YAML definition (using PyYAML):

import yaml

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

         """
    )

print type(x)
print x

Which results in the following output:
<type 'dict'>
{'product': {'sku': 123, 'name': 'Product X', 'features': [{'weight': '10kg', 'size': '10x30cm'}]}}

It is possible to create an object with fields from x?

I would like to the following:

print x.features[0].size

I am aware that it is possible to create and instance from an existing class, but that is not what I want for this particular scenario.

Edit:

  • Updated the confusing part about a 'strongly typed object'.
  • Changed access to features to a indexer as suggested Alex Martelli

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

多情出卖 2024-09-01 19:53:55

因此,您有一个带有字符串键和值的字典,可以是数字、嵌套字典、列表,并且您希望将其包装到一个实例中,该实例允许您使用属性访问来代替字典索引和“使用索引调用”代替列表索引 - 不确定“强类型”与此有何关系,或者为什么您认为 .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能够准确地澄清为什么他可能渴望在动态创建类的元编程高峰之后,他认为他可能会获得什么优势,等等,我将展示如何做到这一点(并且可能,我还将说明为什么人们渴望的优势实际上存在;-)。但简单性在任何编程工作中都是一个重要的品质,当像上面这样简单、直接的代码工作得很好时,使用“深层黑暗魔法”通常不是最好的想法!-)

So you have a dictionary with string keys and values that can be numbers, nested dictionaries, lists, and you'd like to wrap that into an instance which lets you use attribute access in lieu of dict indexing, and "call with an index" in lieu of list indexing -- not sure what "strongly typed" has to do with this, or why you think .features(0) is better than .features[0] (such a more natural way to index a list!), but, sure, it's feasible. For example, a simple approach might be:

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

So x = wrap(x['product']) should give you your wish (why you want to skip that level when your overall logic would obviously require x.product.features(0).size, I have no idea, but clearly that skipping's better applied at the point of call rather than hard-coded in the wrapper class or the wrapper factory function I've just shown).

Edit: as the OP says he does want features[0] rather than features(0), just change the last two lines to

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

i.e., define __getitem__ (the magic method underlying indexing) instead of __call__ (the magic method underlying instance-call).

The alternative to "an existing class" (here, Fourie) would be to create a new class on the fly based on introspecting the wrapped dict -- feasible, too, but seriously dark-gray, if not actually black, magic, and without any real operational advantage that I can think of.

If the OP can clarify exactly why he may be hankering after the meta-programming peaks of creating classes on the fly, what advantage he believes he might be getting that way, etc, I'll show how to do it (and, probably, I'll also show why the craved-for advantage will not in fact be there;-). But simplicity is an important quality in any programming endeavor, and using "deep dark magic" when plain, straightforward code like the above works just fine, is generally not the best of ideas!-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文