mylifcc
V2EX  ›  Python

怎么才能在 Python 中输出一个 key 不带引号的字典呢

By mylifcc at 2022 年 9 月 1 日 · 5508 次点击

或者说这是一个什么样的格式?

比如

{
city: "beijing",
device: "Iphone"
}
37 条回复  •  2022-12-30 16:18:55 +08:00
JamesMackerel
   1
JamesMackerel  
   2022 年 9 月 1 日 via iPhone
可以先序列化再用正则替换一下?
westoy
   2
westoy  
   2022 年 9 月 1 日
js object

popen node.js console.log(json)
Hstar
   3
Hstar  
   2022 年 9 月 1 日
这种格式只存在于代码中,city 和 device 是个变量引用。

输出做不到,非标格式。
caqiko
   4
caqiko  
   2022 年 9 月 1 日 via Android
为什么要这样输出?这是 js 里的对象
yangg
   5
yangg  
   2022 年 9 月 1 日
yaml.dump ?
NessajCN
   6
NessajCN  
   2022 年 9 月 1 日
print("{")
for key in dict:
print(f'{key}:"{dict[key]",')
print("}")
ChrisFreeMan
   8
ChrisFreeMan  
   2022 年 9 月 1 日
找下有没有 json5 的库,json5 就是类似这种格式
mylifcc
   9
mylifcc  
OP
   2022 年 9 月 1 日
@caqiko 源自一个笔试题,不知道怎么生成这种结构,也没查出来
mylifcc
   10
mylifcc  
OP
   2022 年 9 月 1 日
@lisongeee
@ChrisFreeMan 感谢大佬
lanlanye
   11
lanlanye  
   2022 年 9 月 1 日
笔试题的话自己写个遍历打印不就好了吗?

>>> def pprint(dict_):
... print("{")
... for k, v in dict_.items():
... print(f' {k}: "{v}",')
... print("}")
...
>>> d = {'city': 'Beijing', 'device': 'iPhone'}
>>> pprint(d)
{
city: "Beijing",
device: "iPhone",
}
mylifcc
   12
mylifcc  
OP
   2022 年 9 月 1 日
@lanlanye 主要是想了解怎么用 python 生成这种格式和这种格式是个啥
huangzhe8263
   13
huangzhe8263  
   2022 年 9 月 1 日
这就不是 python 里的标准格式吧
llsquaer
   14
llsquaer  
   2022 年 9 月 1 日
正则替换.
dic_str={'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
result=re.sub(r"'(.*?)': '(.*?)'" , "1\:\"\2\"", dic_str )
print(result)
ysc3839
   15
ysc3839  
   2022 年 9 月 1 日 via Android
自己写个遍历输出就完事了
@mylifcc 是 JavaScript(不是 JSON)的 object 格式
ysc3839
   16
ysc3839  
   2022 年 9 月 1 日
一句话的写法:
'{' + ', '.join((f'{k}: "{v}"' for k, v in t.items())) + '}'
没有考虑值中含有引号的转移,可以看规则自己改成 v.replace('"', '\\"')
wxf666
   17
wxf666  
   2022 年 9 月 1 日
@JamesMackerel
@llsquaer

正则替换,要考虑不少东西的。比如:

1. 键值对里的值,不一定全是字符串,还可以是数字、列表、字典等

2. 就算是『"(.+?)"\s*:』,也有可能是『'"fake_key": value'』,序列化成『"\"fake_key\": value"』,然后被替换成『"\fake_key\": value 』了
mylifcc
   18
mylifcc  
OP
   2022 年 9 月 1 日
@ysc3839 了解了
wxf666
   19
wxf666  
   2022 年 9 月 1 日
@JamesMackerel
@llsquaer

写漏了

然后被替换成『"\fake_key\": value"』了
MasterofNone
   20
MasterofNone  
   2022 年 9 月 1 日
不是啊,OP 要的是字典啊,你们推荐的全转换成 string 了
wxf666
   21
wxf666  
   2022 年 9 月 1 日
@mylifcc 对了,若是 key 包含 " \ : <换行> 等字符,你打算咋表示呢?

{
 \": "引号",
 \\: "斜杠",
 \:: "冒号",
 \n: "换行"
}

这样?
mylifcc
   22
mylifcc  
OP
   2022 年 9 月 1 日
@wxf666 我不知道呀,我只想生成一个 不带引号的 key 的字典?。。。。
ershierdu
   23
ershierdu  
   2022 年 9 月 1 日 via iPhone
之前被迫需要用 Python 解析这种结构的字符串,查了一圈,大家都叫它“bad json”…
thinkershare
   24
thinkershare  
   2022 年 9 月 1 日
@mylifcc 如果你只是需要一个这样的字符串, 那么有非常多办法, 如果你需要一个无属性字典, 那么, 没有办法, 因为字典的 key 必须是一个可以哈希化的值, 而你写的属性名称不是任何类型, 因此没办法实现你要的功能. 作为 key 的键, 必须是一个值, 你需要对象那种普通属性是做不到的.
Vegetable
   25
Vegetable  
   2022 年 9 月 1 日
这个考察应该是递归方向的内容,如果用替换那条路会被各种各样的特殊情况为难。

https://imgur.com/a/PkZDCYZ
LindsayZhou
   26
LindsayZhou  
   2022 年 9 月 1 日   ❤️ 1
Python 的 JSONEncoder 全部是用 Python 写的,没用 C
继承过来重新写一下就行了吧: https://github.com/python/cpython/blob/2ecc195498f3b1256fabc2b66e0d8f6d671fa1d7/Lib/json/encoder.py#L36
mylifcc
   27
mylifcc  
OP
   2022 年 9 月 1 日
@LindsayZhou
@thinkershare 主要是想知道这是个什么东西,因为这个东西看起来不像是语法错误,但我又说不上是什么,也没想着他是什么指定的格式,就想知道什么地方会生成它,然后什么地方会用到
wxf666
   28
wxf666  
   2022 年 9 月 1 日
@mylifcc 这个应该是 js 的对象(字面量)吧: https://zh.javascript.info/object


试着写了一个( v 站排版原因,行首有若干全角空格):

1. 可以是数字、布尔、空值、字符串、列表、字典的随意组合

2. 除了字典的键会直接字符串化外,其他字符串会遵循 json 的要求,不包含控制字符和 \ "(替换为转义字符或十六进制)


from typing import Sequence, Mapping

ESCAPE_TABLE = str.maketrans(
  {chr(i): f'\\u{i:04x}' for i in range(32)} |
  {k: f'\\{v}' for k, v in zip('\b\t\n\f\r\\"', 'btnfr"\\')}
)

def jsonify(obj) -> str:
   if isinstance(obj, str):
     return f'"{obj.translate(ESCAPE_TABLE)}"'
   elif isinstance(obj, Sequence):
     return f"[{', '.join(map(jsonify, obj))}]"
   elif isinstance(obj, Mapping):
     return f"{{{', '.join(f'{k}: {jsonify(v)}' for k, v in obj.items())}}}"
   else:
     return str({
       None: 'null',
       True: 'true',
       False: 'false',
    }.get(obj, obj))
JamesMackerel
   29
JamesMackerel  
   2022 年 9 月 1 日 via iPhone
@wxf666 参考 https://blog.dragonslayer.me/archives/115

虽然性能很低就是了(感觉)。如果要性能,应该可以根据语义去做 pretty print ,感觉是一个 json serializer ?不知道好做不好做。
wxf666
   30
wxf666  
   2022 年 9 月 2 日
@JamesMackerel
@llsquaer
@mylifcc

尝试用正则实现了,可在 regexr.com regex101.com 运行

1. 可以是数字、布尔、空值、字符串、列表、字典的随意组合

2. 除了字典的键会直接字符串化外,其他字符串会遵循 json 的要求,不包含控制字符和 \ "(替换为转义字符或十六进制)


以前写过『用正则去除 不规则 json 中的末项逗号』(如:[1, 2, 3,]),想着拿来改改就好

发现功力不够,必须要用到 (?>...) 特性,来防止回溯(即,碰到 \ 就一定要继续匹配后面的转义字符)

但这也导致 JavaScript 、Golang 、Python 3.10 及以下版本 无法使用( Python 3.11 开始支持了)


正则:"((?:(?>\\?).)*?)"\s*(:)|("(?:\\?.)*?")
替换:$1$2$3
引擎:PCRE


『例子( v 站排版原因,行首有若干全角空格,但不影响)』

[
  "\"fake_key\": value",
   123, true, false, null,
  {
    "key1" : "\n\\\":,]:\\",
    "key2" : "\n\\\":,}:\\",
  },
]


『替换后』

[
  "\"fake_key\": value",
   123, true, false, null,
  {
     key1: "\n\\\":,]:\\",
     key2: "\n\\\":,}:\\",
  },
]
wxf666
   31
wxf666  
   2022 年 9 月 2 日
@mylifcc 28 楼有个小地方写错了,

{k: f'\\{v}' for k, v in zip('\b\t\n\f\r\\"', 'btnfr"\\')}

改成

{k: f'\\{v}' for k, v in zip('\b\t\n\f\r\\"', 'btnfr\\"')}
mylifcc
   32
mylifcc  
OP
   2022 年 9 月 2 日
@wxf666 牛的
js8510
   33
js8510  
   2022 年 9 月 2 日
```
>>> class Key:
... def __repr__(self):
... return "Key"
...
>>>
>>>
>>>
>>> m={Key(), 1}
>>> m
{1, Key}
```

这样不就好了??
gongshuiwen
   34
gongshuiwen  
   2022 年 9 月 2 日
使用非字符串对象作为键就会输出该格式,例如:
class City:
pass


city = City()
print({city: "beijing"})

输出结果为:{<__main__.City object at 0x000001CE970BB608>: 'beijing'}


上面为对象默认的字符串表示形式,可以使用 __repr__ 方法改变对象的字符串表示形式:
class City:
def __repr__(self):
return 'city'


city = City()
print({city: "beijing"})

输入结果为:{city: 'beijing'}

所以字典中不带引号的键说明是一个非字符串对象作为的键吧。
xiaochun41
   35
xiaochun41  
   2022 年 9 月 2 日
楼上和楼上的楼上的分析可以借鉴,python 里面字典打印的时候调用的是 dict 的这个方法 __repr__ ,单说 key 的话 也是调用的 key 的类型对应的 __repr__ 方法。
所以就是两个思路:
1 . 继承 dict ,重新定义一个自己的字典类,重新实现 __repr__
2 . 针对特定的 key ,重新实现 key 的 __repr__方法
pjxxcc
   36
pjxxcc  
   2022 年 9 月 2 日
用数字作为 key ,就不会带引号哦
比如:
>>> d = {1: 'yi', 'a': "A"}
>>> d
{1: 'yi', 'a': 'A'}
>>> print(d)
{1: 'yi', 'a': 'A'}
stonesirsir
   37
stonesirsir  
   2022 年 12 月 30 日
遍历字典,然后用字符串打印出来吧
推荐学习书目
› Learn Python the Hard Way
Python Sites
› PyPI - Python Package Index
› http://diveintopython.org/toc/index.html
› Pocoo
值得关注的项目
› PyPy
› Celery
› Jinja2
› Read the Docs
› gevent
› pyenv
› virtualenv
› Stackless Python
› Beautiful Soup
› 结巴中文分词
› Green Unicorn
› Sentry
› Shovel
› Pyflakes
› pytest
Python 编程
› pep8 Checker
Styles
› PEP 8
› Google Python Style Guide
› Code Style from The Hitchhiker's Guide
© 2026 V2EX · 57ms · 3.9.8.5