python - 如何以python中的功能方式将字符串转换为分层数据结构中的dict?

Posted

技术标签:

【中文标题】python - 如何以python中的功能方式将字符串转换为分层数据结构中的dict?【英文标题】:How to convert a string into dict in hierarchical data scructure the functional way in python? 【发布时间】:2021-11-30 22:43:31 【问题描述】:

假设我有以下 python 数据结构,其中runtimeArgs 包含一个 json 字符串,而不是 python dict。

[
   
      "runid":"57d45a60-2b34-11ec-8b92-16c898d5a004",
      "properties":
         "runtimeArgs":"\"date\":\"2021_10_11\",\"logical.start.time\":\"1634026435347\"",
         "phase-1":"7bc31901-2b34-11ec-9194-42010a0c0054"
      
   ,
   
      "runid":"24f7887e-2b28-11ec-b60c-16c898d5a004",
      "properties":
         "runtimeArgs":"\"date\":\"2021_10_11\",\"logical.start.time\":\"1634021196053\"",
         "phase-1":"4712bfa1-2b28-11ec-8968-42010a0c005a"
      
   
]

# this is working
my_list[0]["properties"]['runtimeArgs']

# this not working
my_list[0]["properties"]['runtimeArgs']['date']

使用for 循环和json.loads() 我可以将其转换为python dict,但我想以更实用的方式执行此操作,例如:ma​​plist comprehension 等等。

这怎么可能?

预期结果:

[
   
      "runid":"57d45a60-2b34-11ec-8b92-16c898d5a004",
      "properties":
         "runtimeArgs":"date":"2021_10_11","logical.start.time":"1634026435347",
         "phase-1":"7bc31901-2b34-11ec-9194-42010a0c0054"
      
   ,
   
      "runid":"24f7887e-2b28-11ec-b60c-16c898d5a004",
      "properties":
         "runtimeArgs":"date":"2021_10_11","logical.start.time":"1634021196053",
         "phase-1":"4712bfa1-2b28-11ec-8968-42010a0c005a"
      
   
]

# this should work
my_list[0]["properties"]['runtimeArgs']['date']

更新:

我可以自己解决的一种方法(我不喜欢)是这样的:

[**x, "properties":  "runtimeArgs" : json.loads(x["properties"]["runtimeArgs"])  for x in my_list if x]

有更好的方法吗?

【问题讨论】:

【参考方案1】:

对于这组特定的数据,您可以这样做:

L = [
   
      "runid":"57d45a60-2b34-11ec-8b92-16c898d5a004",
      "properties":
         "runtimeArgs":"\"date\":\"2021_10_11\",\"logical.start.time\":\"1634026435347\"",
         "phase-1":"7bc31901-2b34-11ec-9194-42010a0c0054"
      
   ,
   
      "runid":"24f7887e-2b28-11ec-b60c-16c898d5a004",
      "properties":
         "runtimeArgs":"\"date\":\"2021_10_11\",\"logical.start.time\":\"1634021196053\"",
         "phase-1":"4712bfa1-2b28-11ec-8968-42010a0c005a"
      
   
]

for d in L:
    print(eval(d['properties']['runtimeArgs'])['date'])

【讨论】:

json.loads 可能比 eval 更安全,除非 OP 真的知道数据永远是安全的...... @2e0byo 请注意我在回答开头的评论 - 即,这可能不是解决此问题的通用方法【参考方案2】:

退后一点,你为什么要这样做?以下是我能想到的几个原因,以及适当的解决方案:

因为我想自己实现 JSON 解析器,在功能上,用于实践

在这种情况下,您主要靠自己,但可迭代的标记器可能是要走的路。

因为像从这个 json 格式的字符串中获取元素 x 这样简单的事情应该很容易,而且我只需要这样做一次

在这种情况下,请使用 json.loads,但将您的访问权限包装在一个函数中:

def get_json(json, key):
    return json.loads(json)[key]

get_json(l[0]["properties"], "date") # this is a function.  I reckon that's functional.  Here with a comprehension:

l["runid"]: get_json(x["properties"], "date") for x in l

因为我想从结构中取出数据,在进行时反序列化

使用函数:

def get_parse(thing, key):
    try:
        return thing[key]
    except ValueError:
        return json.loads(thing)[key]

get_parse(get_parse(l[0], "properties"), "date")

如果你愿意,这个函数可以递归,返回最里面的元素。

我不知道这些原因是否正确涵盖了您的用例,但它们可能会有所帮助。基本方法(亲爱的函数式编程!)是将困难的逻辑放在一个函数中,然后如果你愿意,可以在你的理解中使用它。

JIT 解析解决方案

纯粹是为了好玩,因为这是在唠叨我,这里是一个类似JS的JIT解析类:

from json import loads


class JITParser:
    def __init__(self, thing):
        if not hasattr(thing, "__getitem__"):
            self._thing = loads(thing)
        else:
            self._thing = thing

    def get(self, key):
        val = self._thing[key]
        if isinstance(val, dict):
            return JITParser(val)
        else:
            try:
                return JITParser(loads(val))
            except ValueError:
                return val

    def __repr__(self):
        return f"JITParser with repr(self._thing)"


L = [
    
        "runid": "57d45a60-2b34-11ec-8b92-16c898d5a004",
        "properties": 
            "runtimeArgs": '"date":"2021_10_11","logical.start.time":"1634026435347"',
            "phase-1": "7bc31901-2b34-11ec-9194-42010a0c0054",
        ,
    ,
    
        "runid": "24f7887e-2b28-11ec-b60c-16c898d5a004",
        "properties": 
            "runtimeArgs": '"date":"2021_10_11","logical.start.time":"1634021196053"',
            "phase-1": "4712bfa1-2b28-11ec-8968-42010a0c005a",
        ,
    ,
]

j = JITParser(L[0])
j.get("runid")
j.get("properties")
j.get("properties").get("runtimeArgs")
j.get("properties").get("runtimeArgs").get("date")

该类将解析dicts或dicts的json表示,并返回包装它们的JITParser对象,直到遇到无法解析为JSON的东西,在这种情况下,它将返回对象本身。

有很多可能的改进:你可以想到:

子类 dict 并拥有[] 访问权限 实现列表的递归解析 处理其他类型,例如带有.dotaccess 的对象。 等

但是模拟很有趣,它可能会激发你的灵感,所以我将把它留在这里。试试吧:这很有趣。

【讨论】:

以上是关于python - 如何以python中的功能方式将字符串转换为分层数据结构中的dict?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式列出 C++ 或 Python 中的 DLL 依赖项?

如何使用 python 以编程方式计算存档中的文件数

如何在 Python 中以不同方式处理列表中的最后一个元素?

如何以编程方式更改/更新 Python PyQt4 TableView 中的数据?

如何以编程方式从 Python 中的融合模式注册表中获取模式

如何以半自动方式迁移 SQLAlchemy for PostgreSQL 中的新 Python Enum 成员?