OrderedDict理解
我可以在python扩展语法为其他字典的词典的理解,如collections
的OrderedDict模块或从dict
inheritance我自己的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.py
, realmain.py
和main.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编译的字节码,
- 解释器运行这些字节码的方式,或者
-
PyDict
types的实现
坏消息是,虽然所有这些比改变语法要容易得多,但是它们都不能从扩展模块中完成。 (好吧,你可以通过做基本上与纯Python完全相同的事情来完成第一个工作,并且可以通过挂接.so / .dll / .dylib来修补自己的函数来完成其中的任何工作,但这是与Python的黑客攻击以及在运行时挂钩的额外工作完全相同。)
如果你想破解CPython源代码,你想要的代码是Python/compile.c
, Python/ceval.c
和Objects/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)])