OrderedDict理解

 小仙女 发布于 2023-02-03 10:03

我可以在python中为其他dicts的dict comprehension扩展语法,比如collections模块中的OrderedDict 或继承自我自己的类型dict吗?

重新绑定dict名称显然不起作用,{key: value}理解语法仍然为您提供了一个简单的旧词典,用于理解和文字.

>>> from collections import OrderedDict
>>> olddict, dict = dict, OrderedDict
>>> {i: i*i for i in range(3)}.__class__

那么,如果可能的话我该怎么做呢?如果它只适用于CPython,那就没关系.对于语法,我想我会尝试使用O{k: v}像我们一样的前缀r'various' u'string' b'objects'.

注意: 当然我们可以使用生成器表达式,但我更感兴趣的是看到语法方面的hathon是多么糟糕.

3 个回答
  • 对不起,不可能.Dict文字和字典理解以一种在C级硬编码的方式映射到内置字典类型.这不能被覆盖.

    但是,您可以使用此替代方法:

    OrderedDict((i, i * i) for i in range(3))
    

    附录:从Python 3.6开始,所有Python词典都是有序的.从3.7开始,它甚至是语言规范的一部分.如果您正在使用这些版本的Python,则不需要OrderedDict:dict理解将为Just Work(TM).

    2023-02-03 10:04 回答
  • 没有直接的方法可以在语言中更改Python的语法.字典理解(或简单显示)总是会创建一个dict,而你无能为力.如果您正在使用CPython,它会使用直接生成dict的特殊字节码,最终调用PyDictAPI函数和/或该API使用的相同底层函数.如果您正在使用PyPy,那么这些字节码将在RPython dict对象之上实现,而RPython 对象又在已编译和优化的Python之上实现dict.等等.

    有一种间接的方式来做,但你不会喜欢它.如果您阅读导入系统上的文档,您将看到它是导入器,它搜索缓存的已编译代码或调用编译器,以及调用解析器的编译器,依此类推.在Python 3.3+中,这个链中的几乎所有东西都是用纯Python编写的,或者有一个替代的纯Python实现,这意味着你可以分叉代码并做自己的事情.其中包括使用您自己的构建AST的PyParsing代码解析源代码,或者将dict理解AST节点编译成您自己的自定义字节码而不是默认字节码,或者后处理字节码,或者......

    在许多情况下,导入钩子就足够了; 如果没有,您可以随时编写自定义查找程序和加载程序.

    如果您还没有使用Python 3.3或更高版本,我强烈建议您在使用这些内容之前进行迁移.在旧版本中,它更难以记录,并且您最终将花费10倍的精力来学习在迁移时将会过时的内容.

    无论如何,如果这种方法听起来很有趣,你可能想看一下MacroPy.您可以从中借用一些代码 - 并且更重要的是,可以了解如何使用这些功能(在文档中没有很好的示例).

    或者,如果你愿意接受不那么酷的东西,你可以用它MacroPy来构建一个"odict理解宏"并使用它.(请注意,MacroPy目前仅适用于Python 2.7,而不是3.x.)你可能无法获得o{…},但是你可以得到od[{…}],这也不算太糟糕.下载od.py,realmain.pymain.py,并运行python main.py,看它的工作.关键是此代码,这需要一个DictionaryCompAST,将其转换为等效GeneratorExpr于键值Tuples,而把它包装在Callcollections.OrderedDict:

    def od(tree, **kw):
        pair = ast.Tuple(elts=[tree.key, tree.value])
        gx = ast.GeneratorExp(elt=pair, generators=tree.generators)
        odict = ast.Attribute(value=ast.Name(id='collections'), 
                              attr='OrderedDict')
        call = ast.Call(func=odict, args=[gx], keywords=[])
        return call
    

    当然,另一种选择是修改Python解释器.

    我建议O{…}你先删除语法思路,然后将正常的dict理解编译成odicts.好消息是,你真的不需要改变语法(超出毛茸茸......),只需要下列之一:

    dictcomps编译的字节码,

    解释器运行这些字节码的方式,或

    PyDict类型的实现

    坏消息虽然所有这些都比改变语法容易得多,但是没有一个可以通过扩展模块完成.(好吧,你可以通过基本上与纯Python做同样的事情来完成第一个......你可以通过挂钩.so/.dll/.dylib来修补你自己的函数中的任何一个,但那是与在Python上进行黑客攻击以及在运行时挂钩的额外工作完全相同.)

    如果你想破解的CPython的来源,你想要的代码是Python/compile.c,Python/ceval.cObjects/dictobject.c,和开发者指南告诉你如何找到你所需要的一切.但是你可能想要考虑攻击PyPy源代码,因为它主要是用Python(而不是C)的一部分编写的.


    作为旁注,即使所有内容都是在Python语言级别完成的,您的尝试也无法奏效.olddict, dict = dict, OrderedDict创建一个dict在模块的全局变量中命名的绑定,它会隐藏内部结构中的名称,但不会替换它.你可以替换内置的东西(嗯,Python并不能保证这一点,但是有一些实现/特定于版本的东西 - 对于我尝试过的每个实现/版本都会发生这种情况......)但你做了什么不是这样做的方式.

    2023-02-03 10:04 回答
  • 略微修改@Max Noel的响应,您可以使用列表推导而不是生成器以有序的方式创建OrderedDict(使用dict理解当然不可能).

    >>> OrderedDict([(i, i * i) for i in range(5)])
    OrderedDict([(0, 0), 
                 (1, 1), 
                 (2, 4), 
                 (3, 9), 
                 (4, 16)])
    

    2023-02-03 10:04 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有