简体   繁体   English

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

[英]TypeError: string indices must be integers while parsing JSON using Python?

I am confuse now why I am not able to parse this JSON string.我现在很困惑为什么我无法解析这个 JSON 字符串。 Similar code works fine on other JSON string but not on this one - I am trying to parse JSON String and extract script from the JSON.类似的代码适用于其他 JSON 字符串,但不适用于这个字符串 - 我正在尝试解析 JSON 字符串并从 JSON 中提取脚本。

Below is my code.下面是我的代码。

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)

So the first print(jsonStr) will print out something like this -所以第一个print(jsonStr)会打印出这样的东西 -

{"script":"#!/bin/bash\necho Hello world1\n"}

And the second print(j) will print out something like this -第二个print(j)将打印出这样的东西 -

{"script":"#!/bin/bash\necho Hello world1\n"}

And then the third print doesn't gets printed out and it gives this error -然后第三次打印没有打印出来,它给出了这个错误 -

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

So I am wondering what wrong I am doing here?所以我想知道我在这里做错了什么?

I have used same above code to parse the JSON and it works fine..我使用上面相同的代码来解析 JSON,它工作正常..

The problem is that jsonStr is a string that encodes some object in JSON, not the actual object.问题是 jsonStr 是一个字符串,它用 JSON 对某个对象进行编码,而不是实际的对象。

You obviously knew it was a string, because you called it jsonStr .您显然知道它是一个字符串,因为您将其称为jsonStr And it's proven by the fact that this line works:这条线有效的事实证明了这一点:

jsonStr = data.decode("utf-8")

So, jsonStr is a string.所以, jsonStr是一个字符串。 Calling json.dumps on a string is perfectly legal.在字符串上调用json.dumps是完全合法的。 It doesn't matter whether that string was the JSON encoding of some object, or your last name;该字符串是某个对象的 JSON 编码还是您的姓氏并不重要; you can encode that string in JSON.您可以在 JSON 中对该字符串进行编码。 And then you can decode that string, getting back the original string.然后您可以解码该字符串,取回原始字符串。

So, this:所以,这个:

j = json.loads(json.dumps(jsonStr))

… is going to give you back the exact same string as jsonStr in j . ... 将返回与j jsonStr完全相同的字符串。 Which you still haven't decoded to the original object.您还没有解码为原始对象。

To do that, just don't do the extra encode:要做到这一点,不要做额外的编码:

j = json.loads(jsonStr)

If that isn't clear, try playing with it an interactive terminal:如果还不清楚,请尝试在交互式终端上使用它:

>>> 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

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

Ok... So for people who are still lost because they are used to JS this is what I understood after having tested multiple use cases :好吧...所以对于那些仍然迷路的人,因为他们已经习惯了 JS,这是我在测试了多个用例后的理解:

  • json.dumps does not make your string ready to be loaded with json.loads . json.dumps不会让您的字符串准备好加载json.loads It will only encode it to JSON specs (by adding escapes pretty much everywhere) !它只会将其编码为 JSON 规范(通过在几乎所有地方添加转义符)!

  • json.loads will transform a correctly formatted JSON string to a python dictionary. json.loads会将格式正确的 JSON 字符串转换为 Python 字典。 It will only work if the JSON follows the JSON specs (no single quotes, uppercase for boolean's first letter, etc).只有当 JSON 遵循 JSON 规范(没有单引号,布尔值的首字母大写等)时,它才会起作用。

Dumping JSON - An encoding story转储 JSON - 一个编码故事

Lets take an example !让我们举个例子!

$ obj = {"foobar": True}

This is NOT json !这不是 json ! This is a python dictionary that uses python types (like booleans).这是一个使用 python 类型(如布尔值)的 python 字典。

True is not compatible with the JSON specs so in order to send this to an API you would have to serialize it to REAL JSON. True与 JSON 规范不兼容,因此为了将其发送到 API,您必须将其序列化为REAL JSON。 That's where json.dumps comes in !这就是json.dumps用武之地!

$ json.dumps({"foobar": True})
'{"foobar": true}'

See ?看到了吗? True became true which is real JSON. True变为true ,这是真正的 JSON。 You now have a string that you can send to the real world.您现在有一个可以发送到现实世界的字符串。 Good job.干得好。

Loading JSON - A decoding story加载 JSON - 一个解码故事

So now lets talk about json.loads .所以现在让我们谈谈json.loads

You have a string that looks like json but its only a string and what you want is a python dictionary.你有一个看起来像 json 的字符串,但它只是一个字符串,你想要的是一个 python 字典。 Lets walk through the following examples :让我们来看看下面的例子:

$ string = '{"foobar": true}'
$ dict = json.loads(string)
{'foobar': True}

Here we have a string that looks like JSON.这里我们有一个看起来像 JSON 的字符串。 You can use json.loads to transform this string in dictionary and do dict["foobar"] which will return True .您可以使用json.loads在字典中转换此字符串并执行dict["foobar"]这将返回True

So, why so many errors ?那么,为什么会有这么多错误呢?

Well, if your JSON looks like JSON but is not really JSON compatible (spec wise), for instance :好吧,如果您的 JSON 看起来像 JSON,但实际上并不兼容 JSON(规范方面),例如:

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

BAM !砰! This is not working because JSON specs wont allow you to have single quotes but only double ones... If you reverse the quotes to '{"foobar": true}' then it will work.这是行不通的,因为 JSON 规范不允许您使用单引号,而只允许使用双引号...如果您将引号反转为'{"foobar": true}'那么它将起作用。

What you probably have tried is :您可能尝试过的是:

string = json.loads(json.dumps("{'foobar': true}"))

This JSON is invalid (check the quotes) and moreover you'll get a string as a results.这个 JSON 是无效的(检查引号),而且你会得到一个字符串作为结果。 Disapointed ?失望? I know...我知道...

  • json.dumps WILL fix you JSON string but will also encode it. json.dumps将修复您的 JSON 字符串,但也会对其进行编码。 The encoding will render json.loads useless even if the JSON is now good to go.即使 JSON 现在可以使用,编码也会使json.loads无用。

You have to understand that json.dumps encodes and json.loads decodes !您必须了解json.dumps编码和json.loads解码!

So what you did here is encode a string and then decode the string.所以你在这里做的是编码一个字符串,然后解码这个字符串。 But its still a string !但它仍然是一个字符串! you haven't done anything to change that fact !你没有做任何事情来改变这个事实! If you want to get it from string to dictionary then you need an extra step... => A second json.loads !如果您想将它从字符串转换字典,那么您需要一个额外的步骤... =>第二个json.loads

Lets try that with a valid JSON (no mean single quotes)让我们尝试使用有效的 JSON(不是单引号)

$ obj = json.loads(json.loads(json.dumps('{"foobar": true}')))
$ obj["foobar"]
True

The json string went through json.dumps and got encoded. json 字符串通过json.dumps并被编码。 Then it when through json.loads where it got decoded (useless...YEAY).然后当它通过json.loads解码时(没用......是的)。 Finaly, it went through json.loads AGAIN and got transformed from string to dictionary.最后,它再次通过json.loads并从字符串转换为字典。 As you can see, using json.dumps only adds a useless step in that situation.如您所见,在这种情况下,使用json.dumps只会增加一个无用的步骤。

One last thing.最后一件事。 If we do the same thing again but with a bad JSON:如果我们再次执行相同的操作,但 JSON 错误:

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

Quotes are wrong here (ain't you getting used to this by now ?).这里的引用是错误的(你现在还不习惯吗?)。 What happend here is that json.dumps fixed your JSON.这里发生的事情是json.dumps修复了你的 JSON。 json.loads removed the fix (lol) and finaly json.loads got the bad JSON which did not change as the first 2 steps canceled each other. json.loads删除了修复 (lol),最后json.loads得到了错误的 JSON,它没有改变,因为前两个步骤相互取消。

TL;DR TL; 博士

In conclusion : Fix you JSON yourself !总之:自己修复 JSON! Don't give to json.loads wrongly formated JSON and don't try to mix json.loads with json.dumps to fix what only you can fix.不要给json.loads格式错误的 JSON,也不要尝试将json.loadsjson.dumps混合来修复只有你能修复的东西。
Hope this helped someone ;-)希望这对某人有所帮助;-)

Disclaimer.免责声明。 I'm no python expert.我不是python专家。
Feel free to challenge this answer in the comment section.随时在评论部分挑战这个答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM