OrderedDict理解

我可以在python扩展语法为其他字典的词典的理解,如collections的OrderedDict模块或从dictinheritance我自己的types?

只要重新绑定dict名称显然不起作用, {key: value}理解语法仍然给你一个普通的理解和文字老字典。

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

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

注意:当然,我们可以用一个生成器expression式来代替,但是我更感兴趣的是用语法来看待可用的python。

在语言中没有直接的方法来改变Python的语法。 字典理解(或简单的显示)总是要创造一个dict ,并且没有什么可以做的。 如果你使用的是CPython,它使用特殊的字节码直接生成一个字典,最终调用PyDict API函数和/或该API使用的相同的底层函数。 如果您使用的是PyPy,那么这些字节码就会在一个RPython dict对象的顶部实现,而这个对象又是在一个经过编译和优化的Python dict之上实现的。 等等。

有一个间接的方法来做到这一点,但你不会喜欢它。 如果您阅读导入系统上的文档,您将看到它是searchcaching编译代码或调用编译器的导入器,以及调用parsing器的编译器等等。 在Python 3.3+中,这个链中几乎所有东西都是用纯Python编写的,或者有一个替代的纯Python实现,这意味着你可以分叉代码并做自己的事情。 其中包括parsing与您自己的PyParsing代码构build的AST,或编译一个字典理解AST节点到您自己的自定义字节码,而不是默认,或后处理的字节码,或…

在很多情况下, import钩子就足够了; 如果没有,你可以随时写一个自定义查找器和加载器。

如果您还没有使用Python 3.3或更高版本,我强烈build议在玩这个东西之前进行迁移。 在较旧的版本中,这种方法比较困难,而且logging不完善,而且最终你会花费10倍的时间去学习一些在迁移时会过时的东西。

无论如何,如果这种方法听起来有趣,你可能想看看MacroPy 。 你可以借用一些代码 – 也许更重要的是,学习如何使用这些function中的一些(在文档中没有好的例子)。

或者,如果你愿意解决一些不太酷的事情,你可以使用MacroPy来构build一个“odict comprehension macro”并使用它。 (请注意,MacroPy目前只适用于Python 2.7,而不是3.x.)你不能完全得到o{…} ,但你可以得到od[{…}] ,这并不算太坏。 下载od.pyrealmain.pymain.py ,运行python main.py来查看它的工作情况。 关键是这个代码,它需要一个DictionaryComp AST,将它转换为关键值Tuple上的一个等价的GeneratorExpr ,并将其封装在一个Call collections.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 

当然,不同的select是修改Python解释器。

我build议先放下O{…}语法思想,然后把正常的词典理解编译成一些内容。 好消息是,你并不需要改变语法(这不仅仅是毛茸茸的……),而只是任何一个:

  • dictcomps编译的字节码,
  • 解释器运行这些字节码的方式,或者
  • PyDicttypes的实现

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

如果你想破解CPython源代码,你想要的代码是Python/compile.cPython/ceval.cObjects/dictobject.c , 开发指南告诉你如何find你需要的一切。 但是你可能想考虑对PyPy源代码进行攻击,因为它主要是用Python的(而不是C的)子集来写的。


作为一个侧面说明,即使所有事情都是在Python语言级别完成的,你的尝试也不会奏效。 olddict, dict = dict, OrderedDict在模块的全局variables中创build了一个名为dict的绑定,它在内buildolddict, dict = dict, OrderedDict了名字,但是并不代替它。 你可以replace内置的东西(当然,Python并不能保证这一点,但是有实现/特定于版本的东西 – 对于我尝试过的每个实现/版本都会发生这种情况),但是你所做的并不是什么没有办法做到这一点。

对不起,不可能。 字典文字和字典的理解映射到内置的字典types,在C级硬编码。 这不能被覆盖。

但是,您可以将其用作替代方法:

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

稍微修改@Max Noel的响应,您可以使用列表理解而不是生成器来以有序的方式创buildOrderedDict(这当然不能使用dict理解)。

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