Python 转储字典的 Json 会抛出 TypeError:keys must be a string

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12734517/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:44:41  来源:igfitidea点击:

Json dumping a dict throws TypeError: keys must be a string

pythonjsonsimplejson

提问by Viren Rajput

I am attempting to convert the following dictinto JSON using json.dumps:

我正在尝试dict使用以下方法将以下内容转换为 JSON json.dumps

 {
     'post_engaged': 36,
     'post_impressions': 491,
     'post_story': 23,
     'comment_count': 6,
     'created_time': '03:02 AM, Sep 30, 2012',
     'message': 'Specialities of Shaktis and Pandavas. \n While having power, why there isn\u2019t',
     < built - in function id > : '471662059541196',
     'status_type': 'status',
     'likes_count': 22
 } {
     'post_engaged': 24,
     'text': '30 Sept 2012 Avyakt Murlli ( Dual Voice )',
     'post_story': 8,
     'comment_count': 3,
     'link': 'http:\/\/www.youtube.com\/watch?v=VGmFj8g7JFA&feature=youtube_gdata_player',
     'post_impressions': 307,
     'created_time': '03:04 AM, Sep 30, 2012',
     'message': 'Not available',
     < built - in function id > : '529439300404155',
     'status_type': 'video',
     'likes_count': 7
 } {
     'post_engaged': 37,
     'post_impressions': 447,
     'post_story': 22,
     'comment_count': 4,
     'created_time': '03:11 AM, Sep 30, 2012',
     'message': '30-09-12 \u092a\u094d\u0930\u093e\u0924:\u092e\u0941\u0930\u0932\u0940 \u0913\u0',
     < built - in function id > : '471643246209744',
     'status_type': 'status',
     'likes_count': 20
 } {
     'post_engaged': 36,
     'post_impressions': 423,
     'post_story': 22,
     'comment_count': 0,
     'created_time': '03:04 AM, Sep 29, 2012',
     'message': 'Essence: Sweet children, whenever you have time, earn the true income. Staying i',
     < built - in function id > : '471274672913268',
     'status_type': 'status',
     'likes_count': 20
 } {
     'post_engaged': 16,
     'text': 'Essence Of Murli 29-09-2012',
     'post_story': 5,
     'comment_count': 2,
     'link': 'http:\/\/www.youtube.com\/watch?v=i6OgmbRsJpg&feature=youtube_gdata_player',
     'post_impressions': 291,
     'created_time': '03:04 AM, Sep 29, 2012',
     'message': 'Not available',
     < built - in function id > : '213046588825668',
     'status_type': 'video',
     'likes_count': 5
 }

But it leads me to

但它使我

TypeError : keys must be a string

The error is likely due to the dict containing, keyslike:

错误可能是由于 dict 包含,keys例如:

 <built-in function id>: '213046588825668'

Can someone please guide me, with how should I remove these elements from the dict?

有人可以指导我,我应该如何从字典中删除这些元素?

采纳答案by bigblind

You could try to clean it up like this:

你可以尝试像这样清理它:

for key in mydict.keys():
  if type(key) is not str:
    try:
      mydict[str(key)] = mydict[key]
    except:
      try:
        mydict[repr(key)] = mydict[key]
      except:
        pass
    del mydict[key]

This will try to convert any key that is not a string into a string. Any key that could not be converted into a string or represented as a string will be deleted.

这将尝试将任何不是字符串的键转换为字符串。任何无法转换为字符串或表示为字符串的键都将被删除。

回答by Donnie

Maybe this will help the next guy:

也许这会帮助下一个人:

strjson = json.dumps(str(dic).replace("'",'"'))

回答by Nolan Conaway

Modifying the accepted answer above, I wrote a function to handle dictionaries of arbitrary depth:

修改上面接受的答案,我写了一个函数来处理任意深度的字典:

def stringify_keys(d):
    """Convert a dict's keys to strings if they are not."""
    for key in d.keys():

        # check inner dict
        if isinstance(d[key], dict):
            value = stringify_keys(d[key])
        else:
            value = d[key]

        # convert nonstring to string if needed
        if not isinstance(key, str):
            try:
                d[str(key)] = value
            except Exception:
                try:
                    d[repr(key)] = value
                except Exception:
                    raise

            # delete old key
            del d[key]
    return d

回答by DeyaEldeen

Nolan conaway's answer gives this result for example

例如,诺兰康纳威的回答给出了这个结果

{"b'opening_hours'": {"b'1_from_hour'": 720, "b'1_to_hour'": 1440, "b'1_break_from_hour'": 1440, "b'1_break_to_hour'": 1440, "b'2_from_hour'": 720, "b'2_to_hour'": 1440, "b'2_break_from_hour'": 1440, "b'2_break_to_hour'": 1440, "b'3_from_hour'": 720, "b'3_to_hour'": 1440, "b'3_break_from_hour'": 1440, "b'3_break_to_hour'": 1440, "b'4_from_hour'": 720, "b'4_to_hour'": 1440, "b'4_break_from_hour'": 1440, "b'4_break_to_hour'": 1440, "b'5_from_hour'": 720, "b'5_to_hour'": 1440, "b'5_break_from_hour'": 1440, "b'5_break_to_hour'": 1440, "b'6_from_hour'": 720, "b'6_to_hour'": 1440, "b'6_break_from_hour'": 1440, "b'6_break_to_hour'": 1440, "b'7_from_hour'": 720, "b'7_to_hour'": 1440, "b'7_break_from_hour'": 1440, "b'7_break_to_hour'": 1440}}

{“b'opening_hours'”:{“b'1_from_hour'”:720,“b'1_to_hour'”:1440,“b'1_break_from_hour'”:1440,“b'1_break_to_hour'”:1440,“b'2_from_hour' ": 720, "b'2_to_hour'": 1440, "b'2_break_from_hour'": 1440, "b'2_break_to_hour'": 1440, "b'3_from_hour'": 720, "b'3_to_hour'": 1440, " b'3_break_from_hour'": 1440, "b'3_break_to_hour'": 1440, "b'4_from_hour'": 720, "b'4_to_hour'": 1440, "b'4_break_from_hour'": 1440, "b'4_小时"break_to :1440,“b'5_from_hour'”:720,“b'5_to_hour'”:1440,“b'5_break_from_hour'": 1440, "b'5_break_to_hour'": 1440, "b'6_from_hour'": 720, "b'6_to_hour'": 1440, "b'6_break_from_hour'": 1440, "b'6_from_hour': 1440 ,“b'7_from_hour'”:720,“b'7_to_hour'”:1440,“b'7_break_from_hour'”:1440,“b'7_break_to_hour'”:1440}}第1440章第1440章

while this amended version

虽然这个修订版

import time
import re
import json
from phpserialize import *


class Helpers:
   def stringify_keys(self,d):
    """Convert a dict's keys to strings if they are not."""
    for key in d.keys():
        # check inner dict
        if isinstance(d[key], dict):
            value = Helpers().stringify_keys(d[key])
        else:
            value = d[key]
        # convert nonstring to string if needed
        if not isinstance(key, str):
            try:
                d[key.decode("utf-8")] = value
            except Exception:
                try:
                    d[repr(key)] = value
                except Exception:
                    raise

            # delete old key
            del d[key]
    return d

will give this cleaner version..

会给这个更干净的版本..

{"opening_hours": {"1_from_hour": 720, "1_to_hour": 1440, "1_break_from_hour": 1440, "1_break_to_hour": 1440, "2_from_hour": 720, "2_to_hour": 1440, "2_break_from_hour": 1440, "2_break_to_hour": 1440, "3_from_hour": 720, "3_to_hour": 1440, "3_break_from_hour": 1440, "3_break_to_hour": 1440, "4_from_hour": 720, "4_to_hour": 1440, "4_break_from_hour": 1440, "4_break_to_hour": 1440, "5_from_hour": 720, "5_to_hour": 1440, "5_break_from_hour": 1440, "5_break_to_hour": 1440, "6_from_hour": 720, "6_to_hour": 1440, "6_break_from_hour": 1440, "6_break_to_hour": 1440, "7_from_hour": 720, "7_to_hour": 1440, "7_break_from_hour": 1440, "7_break_to_hour": 1440}}

{"opening_hours": {"1_from_hour": 720, "1_to_hour": 1440, "1_break_from_hour": 1440, "1_break_to_hour": 1440, "2_from_hour": 720, "2_to_hour": 2_to_hour: 1440, "4_小时_0"4_0_break_0 ": 1440, "3_from_hour": 720, "3_to_hour": 1440, "3_break_from_hour": 1440, "3_break_to_hour": 1440, "4_from_hour": 720, "4_to_hour": 1440, "4_hour": 1440, "4_小时:"4_小时1440, "5_from_hour": 720, "5_to_hour": 1440, "5_break_from_hour": 1440, "5_break_to_hour": 1440, "6_from_hour": 720, "6_to_hour": 1440, "6_to_hour": 4_0_break_6:1440 “7_from_hour”:720,“7_to_hour”:1440,“7_break_from_hour”:1440,“7_break_to_hour”:1440}}

回答by rite2hhh

Ideally you would want to clean your data so you comply to the data types supported by JSON.

理想情况下,您希望清理数据,以便符合 JSON 支持的数据类型。

If you simply want to suppress/ or remove these elements from the dict while serializing, you can use skipkeysargument, description can be found in json.dumpsection

如果您只是想在序列化时从 dict 中抑制/或删除这些元素,您可以使用skipkeys参数,描述可以在部分中找到json.dump

If skipkeys is true (default: False), then dict keys that are not of a basic type (str, int, float, bool, None) will be skipped instead of raising a TypeError.

如果skipkeys 为true(默认值:False),则将跳过不是基本类型(str、int、float、bool、None)的dict 键,而不是引发TypeError。

json.dumps(obj, skipkeys=True)

This solution is much cleaner and allows the standard library handle erroneous keys for you.

此解决方案更简洁,并允许标准库为您处理错误的键。

WARNING: You must fully understand the implications of using such a drastic method as this will result in data loss for non-compliant data types as JSON keys.

警告:您必须完全理解使用这种极端方法的含义,因为这将导致不合规数据类型(如 JSON 键)的数据丢失。

回答by Iván B.

Maybe this will help:

也许这会有所帮助:

your_dict = {("a", "b"):[1,2,3,4]}
# save
with open("file.json","w") as f:
    f.write(json.dumps(list(your_dict.items())))

# load
with open("file.json","r") as f:
    your_dict = dict([tuple((tuple(x[0]), x[1])) for x in json.loads(f.read())])

回答by bruno desthuilliers

I know this is an old question and it already has an accepted answer, but alas the accepted answer is just totally wrong.

我知道这是一个古老的问题,它已经有一个公认的答案,但遗憾的是,公认的答案是完全错误的。

The real issue here is that the code that generates the dict uses the builtin idfunction as key instead of the literal string "id". So the simple, obvious and only correctsolution is to fix this bug at the source : check the code that generates the dict, and replace idwith "id".

这里真正的问题是生成 dict 的代码使用内置id函数作为键而不是文字 string "id"。因此,简单、明显且唯一正确的解决方案是从源头修复此错误:检查生成 dict 的代码,并替换id"id".