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

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

编辑:

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

解决方案

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top