TypeError:使用Python解析JSON时,字符串索引必须是整数?

AKI*_*WEB 21 python parsing json

我现在很困惑为什么我无法解析这个JSON字符串.类似的代码在其他JSON字符串上工作正常但不在这一个 - 我试图解析JSON字符串并从JSON中提取脚本.

以下是我的代码.

for step in steps:
    step_path = '/example/v1' +'/'+step

    data, stat = zk.get(step_path)
    jsonStr = data.decode("utf-8")
    print(jsonStr)
    j = json.loads(json.dumps(jsonStr))
    print(j)
    shell_script = j['script']
    print(shell_script)
Run Code Online (Sandbox Code Playgroud)

所以第一个print(jsonStr)会打印出这样的东西 -

{"script":"#!/bin/bash\necho Hello world1\n"}
Run Code Online (Sandbox Code Playgroud)

第二个print(j)会打印出这样的东西 -

{"script":"#!/bin/bash\necho Hello world1\n"}
Run Code Online (Sandbox Code Playgroud)

然后第三次打印没有打印出来,它给出了这个错误 -

Traceback (most recent call last):
  File "test5.py", line 33, in <module>
    shell_script = j['script']
TypeError: string indices must be integers
Run Code Online (Sandbox Code Playgroud)

所以我想知道我在这里做错了什么?

我使用相同的上面的代码来解析JSON,它工作正常..

aba*_*ert 33

问题是jsonStr是一个字符串,它编码JSON中的某个对象,而不是实际的对象.

你显然知道它是一个字符串,因为你打电话给它jsonStr.事实证明,这条生产线的工作原理是:

jsonStr = data.decode("utf-8")
Run Code Online (Sandbox Code Playgroud)

所以,jsonStr是一个字符串.调用json.dumps字符串是完全合法的.该字符串是否是某个对象的JSON编码或您的姓氏并不重要; 你可以用JSON编码该字符串.然后你可以解码该字符串,获取原始字符串.

所以这:

j = json.loads(json.dumps(jsonStr))
Run Code Online (Sandbox Code Playgroud)

......是想给你回完全相同的字符串jsonStrj.你仍然没有解码到原始对象.

要做到这一点,只是不要做额外的编码:

j = json.loads(jsonStr)
Run Code Online (Sandbox Code Playgroud)

如果不清楚,请尝试使用交互式终端:

>>> obj = ['abc', {'a': 1, 'b': 2}]
>>> type(obj)
list
>>> obj[1]['b']
2
>>> j = json.dumps(obj)
>>> type(j)
str
>>> j[1]['b']
TypeError: string indices must be integers
>>> jj = json.dumps(j)
>>> type(jj)
str
>>> j
'["abc", {"a": 1, "b": 2}]'
>>> jj
'"[\\"abc\\", {\\"a\\": 1, \\"b\\": 2}]"'
>>> json.loads(j)
['abc', {'a': 1, 'b': 2}]
>>> json.loads(j) == obj
True
>>> json.loads(jj)
'["abc", {"a": 1, "b": 2}]'
>>> json.loads(jj) == j
True
>>> json.loads(jj) == obj
False
Run Code Online (Sandbox Code Playgroud)

  • 投票最多:因为您做的不只是说要用b替换a ...您还对原因做了一些解释,并尝试显示有关调试的示例。 (2认同)

1st*_*st1 21

尝试更换j = json.loads(json.dumps(jsonStr))j = json.loads(jsonStr).

  • @tMJ:没有"JSON对象"这样的东西.当人们这么说时,他们的一半时间意味着"可以用JSON编码的Python(或JavaScript或其他)对象",而有一半的时间意味着"字符串是对象的JSON表示".我不知道你指的是哪一个.我怀疑你也没有.只是不要使用那个术语.显然,`zk.get`返回的值是一个`bytes`对象,因为你可以在它上面调用`.decode('utf-8')`.据推测,它是字符串的UTF-8编码,它是对象的JSON表示. (3认同)

Doc*_*tor 10

好吧...所以对于那些因为习惯了 JS 而仍然迷失方向的人来说,这是我在测试了多个用例后所理解的:

  • json.dumps不会使您的字符串准备好加载json.loads。它只会将其编码为 JSON 规范(通过在几乎所有地方添加转义符)!

  • json.loads会将格式正确的 JSON 字符串转换为 Python 字典。仅当 JSON 遵循 JSON 规范(无单引号、布尔值的第一个字母大写等)时,它才有效。

转储 JSON - 一个编码故事

让我们举个例子!

$ obj = {"foobar": True}
Run Code Online (Sandbox Code Playgroud)

这不是 json !这是一个使用 python 类型(如布尔值)的 python 字典。

True与 JSON 规范不兼容,因此为了将其发送到 API,您必须将其序列化为REAL JSON。这就是json.dumps进来的地方!

$ json.dumps({"foobar": True})
'{"foobar": true}'
Run Code Online (Sandbox Code Playgroud)

看 ?True变成了true真正的 JSON。您现在有了一个可以发送到现实世界的字符串。好工作。

加载 JSON - 一个解码故事

那么现在我们来谈谈json.loads

你有一个看起来像 json 的字符串,但它只是一个字符串,你想要的是一个 python 字典。让我们看一下以下示例:

$ string = '{"foobar": true}'
$ dict = json.loads(string)
{'foobar': True}
Run Code Online (Sandbox Code Playgroud)

这里我们有一个看起来像 JSON 的字符串。您可以使用json.loads在字典中转换此字符串并执行操作dict["foobar"]将返回True

那么,为什么会有这么多错误呢?

好吧,如果您的 JSON 看起来像 JSON,但实际上并不兼容 JSON(规范方面),例如:

$ string = "{'foobar': true}"
$ json.loads(string)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes
Run Code Online (Sandbox Code Playgroud)

嘭!这是行不通的,因为 JSON 规范不允许你使用单引号,而只允许使用双引号...如果你反转引号,那么'{"foobar": true}'它就会工作。

您可能尝试过的是:

string = json.loads(json.dumps("{'foobar': true}"))
Run Code Online (Sandbox Code Playgroud)

此 JSON 无效(检查引号),而且您将得到一个字符串作为结果。失望吗?我知道...

  • json.dumps将修复您的 JSON 字符串,但也会对其进行编码。json.loads即使 JSON 现在可以使用,编码也会变得毫无用处。

你必须了解json.dumps编码和json.loads解码!

因此,您在这里所做的就是对字符串进行编码,然后对字符串进行解码。但它仍然是一个字符串!你没有做任何事情来改变这个事实!如果你想将它从字符串获取到字典,那么你需要一个额外的步骤... =>第二步json.loads

让我们尝试使用有效的 JSON(不是单引号)

$ obj = json.loads(json.loads(json.dumps('{"foobar": true}')))
$ obj["foobar"]
True
Run Code Online (Sandbox Code Playgroud)

json 字符串经过json.dumps并被编码。然后它通过json.loads解码的地方(没用......是的)。最后,它再次经历json.loads并从字符串转换为字典。正如您所看到的,json.dumps在这种情况下使用只会增加一个无用的步骤。

最后一件事。如果我们再次执行相同的操作,但 JSON 格式错误:

$ string = json.loads(json.loads(json.dumps("{'foobar': true}")))
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes
Run Code Online (Sandbox Code Playgroud)

这里的引号是错误的(你现在还没习惯吗?)。这里发生的事情json.dumps修复了你的 JSON。json.loads删除了修复程序(笑),最终json.loads得到了错误的 JSON,该 JSON 没有改变,因为前 2 个步骤相互抵消了。

长话短说

结论:自己修复 JSON!不要使用json.loads格式错误的 JSON,也不要尝试混合json.loadsjson.dumps修复只有您可以修复的内容。
希望这对某人有帮助;-)

免责声明。我不是Python专家。
欢迎在评论部分质疑这个答案。