题
我有以下 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能够准确地澄清为什么他可能渴望在动态创建类的元编程高峰之后,他认为他可能会获得什么优势,等等,我将展示如何做到这一点(并且可能,我还将展示为什么渴望的优势会 不是 事实上就在那里;-)。但简单性在任何编程工作中都是一个重要的品质,当像上面这样简单、直接的代码工作得很好时,使用“深层黑暗魔法”通常不是最好的想法!-)