【问题标题】:Dynamically "objectify" a nested data structure with python-attrs使用 python-attrs 动态“对象化”嵌套数据结构
【发布时间】:2018-07-07 00:16:27
【问题描述】:

对于任意字典(最终包含嵌套集合和基本类型),使用 python-attrs 使其成为嵌套对象列表的最佳方法是什么?

一些限制:字典键始终是字符串(它们是有效的 Python 标识符),其值将仅包含本机集合类型、字符串、整数和浮点数。任何完全深度的嵌套字典都将始终具有相同的特征。在任何列表或元组中,所有项目都将是相同类型或无。而且很可能我的字典将始终是有序映射,因此应该在生成的顶级列表和每个嵌套映射中保留顺序。

例如与:

{'some_key': [
  {'some_value': 12, 'foo': 'abc', 'bar': [1, 4, 8], 'baz': None}
  {'some_value': 24, 'foo': 'xyz', 'bar': [12, 12], 'baz': 'this'}],
 'other_key' : [1,2,3,4]
}

我想得到一个可以使用属性遍历的两个对象的列表:

some_key[0].some_value, some_key[0].baz 
other_key[-1]

即结果将是“对象化”嵌套映射。我怎么能用 attrs 做到这一点?有attr.make_class() 的循环调用要走的路吗?

【问题讨论】:

    标签: pytest python-attrs


    【解决方案1】:

    所以最终我想出了一个稍微不同的客观化解决方案(并且可以很容易地扩展):

    这是使用attr.make_class。在我的情况下,“pluggy”插件类(pluggy 是使用的插件库,来自py.test)正在为数据object 贡献新的data attributes。 然后我调用make_class 来构建我的数据类的新子类,向该子类添加新的attr.ib 属性。我本可以避免声明这些属性,而是通过对贡献属性的数据类型的递归自省来动态构建它们……但我选择了显式而不是隐式;)

    在此过程中,有一个小的bug 在类主体之外创建的attr.ibs 可能无法使用我期望的顺序附加到新的子类,@hynek 很快解决了这个问题

    【讨论】:

      【解决方案2】:

      说明您为什么要拥有对象而不是简单地使用字典可能会有所帮助。您的示例用法是:

      some_key[0].some_value, some_key[0].baz 
      other_key[-1]
      

      区别在于:

      some_key[0]["some_value"], some_key[0]["baz"]
      other_key[-1]
      

      您在此处寻找点访问语法的唯一方法是什么?

      attrs 的意思是为您提供一种更简单地定义类的方法,而不是将非结构化数据包装到非预定义类型的对象中的方法,因此这不像是用例 @ 987654324@,attrs 的目标地址。

      【讨论】:

      • "您在这里寻找的唯一的东西是获取点访问语法吗?" : ..... 是的,这对插件创建者来说是一个有效的 API 可用性问题。这意味着最终生成带有 attrs 的新类型,我现在做得很好。感谢您首先尝试找到与需求有关的问题,但我认为这是一个有效的问题,并且 attrs 也是解决此问题的有效方法!
      • FWIW,cattrs 似乎也在 attrs 之上解决了这个问题。基本上,问题是对我喜欢使用 attrs 的对象的任意嵌套数据进行反序列化/序列化。
      • 来自 attrs 文档:if your dict has a fixed and known set of keys, it is an object, not a hash. So if you never iterate over the keys of a dict, you should use a proper class. 我认为这是理由。
      【解决方案3】:

      我不知道您为什么要为此使用 attrs,因为为此目的有特定的库:Box

      from box import Box
      
      a_dict = {'some_key': [
          {'some_value': 12, 'foo': 'abc', 'bar': [1, 4, 8], 'baz': None},
          {'some_value': 24, 'foo': 'xyz', 'bar': [12, 12], 'baz': 'this'}],
          'other_key': [1, 2, 3, 4]
      }
      
      box_dict = Box(a_dict)
      
      assert box_dict.some_key[0].some_value == 12
      assert box_dict.some_key[0].baz == None
      assert box_dict.other_key[-1] == 4
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-23
        • 2021-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多