【问题标题】:Accessing json data by a list of strings?通过字符串列表访问 json 数据?
【发布时间】:2017-10-23 21:37:42
【问题描述】:

我有这个 json:

json = {
    "state": {
        "reported": {
            "figure": {"x":10, "y":12, "z":12},
            "gif": {"x":10,"y":12, "z":12}
        }
    }
}

还有这个字符串列表:

lista = ["json['state']['reported']['figure']['x']",
         "json['state']['reported']['figure']['y']",
         "json['state']['reported']['gif']['z']"]

我想知道是否有办法使用此列表获取 json 的结果?

【问题讨论】:

  • 您可以使用 regex 获取列表中的 dict 键,然后递归地从您的 json 对象中获取值。但理想情况下,您应该更改逻辑以在列表中形成该字符串,并尽可能创建键列表
  • 这是一种不安全但有效的方法:result = [eval(item) for item in lista]
  • 硬编码数据并不那么不安全
  • 请不要为此使用eval(或任何与此相关的)。有一些像 jsonpath 这样的模块就是为此目的而设计的。
  • @zwer 我不明白为什么每个人都反对 eval。当然 eval(input()) 正在乞求代码 inj,但是这个 x = eval('1') 有什么问题?

标签: python arrays json python-2.7 dictionary


【解决方案1】:

正如另一个答案中指出的那样,您可以为此使用eval。甚至还有一些技巧可以让黑客更难控制您的系统。这是迄今为止最简单的路线,但是,没有明确的方法可以使其真正安全。你玩的这些花招只会给你一种虚假的安全感。因此,如果您不完全信任lista 的来源,请不要使用它。坏事会发生。

好消息是,如果您愿意编写(或复制/粘贴)更多代码,我们可以使用 python 的 AST 安全地完成此操作。诀窍是将字符串解析为 AST。然后,我们将创建一个可以遍历 AST 并在找到某些类型的节点时采取适当(和安全)操作的类。在您的示例中,我们需要处理 4 种类型的节点:

  • Str:表示字符串字面量。
  • Name:表示名称查找。例如json
  • Subscript:代表__getitem__ 调用。
  • Index:将传递给__getitem__ 的对象。一般来说,这也可以是一个切片 - 但这不在您显示的输入中,因此我们暂时不支持它。

您可能需要的其他类型的节点(取决于输入)是NumSlice。一旦您了解了ast reference(如果您以前没有看过它可能会有些晦涩),就应该直接实施它们。

现在编写我们的类开始看起来很简单:

class Evaluator(ast.NodeVisitor):
    def __init__(self, globals):
        self._globals = globals

    def visit_Str(self, n):
        return n.s

    def visit_Name(self, n):
        return self._globals[n.id]

    def visit_Subscript(self, n):
        item = self.visit(n.value)
        slce = self.visit(n.slice)
        return item[slce]

    def visit_Index(self, n):
        return self.visit(n.value)

    def visit_Expr(self, n):
        return self.visit(n.value)

实际上,它看起来像:

e = Evaluator({'json': json})
print([e.visit(ast.parse(s).body[0]) for s in lista])

【讨论】:

  • 你能告诉我如何使用这个脚本,例如:json1=json.dumps(json) ???????
  • @Adler:您的后续问题没有任何意义,因为您尝试使用json 来表示json 模块问题中的字典变量.您可以使用import json as json_module 来避免这种情况,这将允许您编写json1 = json_module.dumps(json)e = Evaluator({'json': json}),然后是print([e.visit(ast.parse(s).body[0]) for s in lista])
【解决方案2】:

你可以使用 python 的 eval 函数。话虽如此,这是一个非常糟糕的主意,因为 eval 是一个危险的函数。有关 eval 函数的更多信息,请查看此链接:https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html

json = {
    "state": {
        "reported": {
            "figure": {"x": 10, "y": 12, "z": 12},
            "gif": {"x": 10, "y": 12, "z": 12}
        }}}

lista = [
    "json['state']['reported']['figure']['x']",
    "json['state']['reported']['figure']['y']",
    "json['state']['reported']['gif']['z']"
]

values = [eval(x) for x in lista]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多