V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
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
mylifcc
V2EX  ›  Python

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

  •  
  •   mylifcc · 2022-09-01 16:19:58 +08:00 · 4151 次点击
    这是一个创建于 819 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    比如

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

    popen node.js console.log(json)
    Hstar
        3
    Hstar  
       2022-09-01 16:30:15 +08:00
    这种格式只存在于代码中,city 和 device 是个变量引用。

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

    >>> 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-09-01 17:49:40 +08:00
    @lanlanye 主要是想了解怎么用 python 生成这种格式和这种格式是个啥
    huangzhe8263
        13
    huangzhe8263  
       2022-09-01 18:22:16 +08:00
    这就不是 python 里的标准格式吧
    llsquaer
        14
    llsquaer  
       2022-09-01 18:52:09 +08:00
    正则替换.
    dic_str={'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
    result=re.sub(r"'(.*?)': '(.*?)'" , "1\:\"\2\"", dic_str )
    print(result)
    ysc3839
        15
    ysc3839  
       2022-09-01 18:59:09 +08:00 via Android
    自己写个遍历输出就完事了
    @mylifcc 是 JavaScript(不是 JSON)的 object 格式
    ysc3839
        16
    ysc3839  
       2022-09-01 19:09:32 +08:00
    一句话的写法:
    '{' + ', '.join((f'{k}: "{v}"' for k, v in t.items())) + '}'
    没有考虑值中含有引号的转移,可以看规则自己改成 v.replace('"', '\\"')
    wxf666
        17
    wxf666  
       2022-09-01 19:12:12 +08:00
    @JamesMackerel
    @llsquaer

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

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

    2. 就算是『"(.+?)"\s*:』,也有可能是『'"fake_key": value'』,序列化成『"\"fake_key\": value"』,然后被替换成『"\fake_key\": value 』了
    mylifcc
        18
    mylifcc  
    OP
       2022-09-01 19:12:36 +08:00
    @ysc3839 了解了
    wxf666
        19
    wxf666  
       2022-09-01 19:17:40 +08:00
    @JamesMackerel
    @llsquaer

    写漏了

    然后被替换成『"\fake_key\": value"』了
    mmm159357456
        20
    mmm159357456  
       2022-09-01 20:03:39 +08:00
    不是啊,OP 要的是字典啊,你们推荐的全转换成 string 了
    wxf666
        21
    wxf666  
       2022-09-01 20:21:36 +08:00
    @mylifcc 对了,若是 key 包含 " \ : <换行> 等字符,你打算咋表示呢?

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

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

    https://imgur.com/a/PkZDCYZ
    LindsayZhou
        26
    LindsayZhou  
       2022-09-01 21:49:43 +08:00   ❤️ 1
    Python 的 JSONEncoder 全部是用 Python 写的,没用 C
    继承过来重新写一下就行了吧: https://github.com/python/cpython/blob/2ecc195498f3b1256fabc2b66e0d8f6d671fa1d7/Lib/json/encoder.py#L36
    mylifcc
        27
    mylifcc  
    OP
       2022-09-01 22:03:34 +08:00
    @LindsayZhou
    @thinkershare 主要是想知道这是个什么东西,因为这个东西看起来不像是语法错误,但我又说不上是什么,也没想着他是什么指定的格式,就想知道什么地方会生成它,然后什么地方会用到
    wxf666
        28
    wxf666  
       2022-09-01 22:35:52 +08:00
    @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-09-01 22:43:49 +08:00 via iPhone
    @wxf666 参考 https://blog.dragonslayer.me/archives/115

    虽然性能很低就是了(感觉)。如果要性能,应该可以根据语义去做 pretty print ,感觉是一个 json serializer ?不知道好做不好做。
    wxf666
        30
    wxf666  
       2022-09-02 00:30:51 +08:00
    @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-09-02 00:38:13 +08:00
    @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-09-02 01:10:33 +08:00
    @wxf666 牛的
    js8510
        33
    js8510  
       2022-09-02 01:59:34 +08:00
    ```
    >>> class Key:
    ... def __repr__(self):
    ... return "Key"
    ...
    >>>
    >>>
    >>>
    >>> m={Key(), 1}
    >>> m
    {1, Key}
    ```

    这样不就好了??
    gongshuiwen
        34
    gongshuiwen  
       2022-09-02 10:21:17 +08:00
    使用非字符串对象作为键就会输出该格式,例如:
    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-09-02 10:44:07 +08:00
    楼上和楼上的楼上的分析可以借鉴,python 里面字典打印的时候调用的是 dict 的这个方法 __repr__ ,单说 key 的话 也是调用的 key 的类型对应的 __repr__ 方法。
    所以就是两个思路:
    1 . 继承 dict ,重新定义一个自己的字典类,重新实现 __repr__
    2 . 针对特定的 key ,重新实现 key 的 __repr__方法
    pjxxcc
        36
    pjxxcc  
       2022-09-02 11:06:53 +08:00
    用数字作为 key ,就不会带引号哦
    比如:
    >>> d = {1: 'yi', 'a': "A"}
    >>> d
    {1: 'yi', 'a': 'A'}
    >>> print(d)
    {1: 'yi', 'a': 'A'}
    stonesirsir
        37
    stonesirsir  
       2022-12-30 16:18:55 +08:00
    遍历字典,然后用字符串打印出来吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1192 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 22:54 · PVG 06:54 · LAX 14:54 · JFK 17:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.