Python 有序理解
我是否可以扩展python中的语法来理解其他dict,如Python 有序理解,python,dictionary,cpython,ordereddictionary,dictionary-comprehension,Python,Dictionary,Cpython,Ordereddictionary,Dictionary Comprehension,我是否可以扩展python中的语法来理解其他dict,如集合模块中的OrderedDict或从dict继承的我自己的类型 仅仅重新绑定dict名称显然不起作用,{key:value}理解语法仍然为理解和文字提供了一个简单的旧dict >>> from collections import OrderedDict >>> olddict, dict = dict, OrderedDict >>> {i: i*i for i in range(3
集合
模块中的OrderedDict或从dict
继承的我自己的类型
仅仅重新绑定dict
名称显然不起作用,{key:value}
理解语法仍然为理解和文字提供了一个简单的旧dict
>>> from collections import OrderedDict
>>> olddict, dict = dict, OrderedDict
>>> {i: i*i for i in range(3)}.__class__
<type 'dict'>
>>从集合导入订单数据
>>>olddict,dict=dict,OrderedDict
>>>{i:i*i表示范围(3)}.\u类__
那么,如果可能的话,我该怎么做呢?如果它只在CPython中起作用就可以了。对于语法,我想我会尝试使用O{k:v}
前缀,就像我们在r'各种'u'字符串'b'对象'
上一样
注意:当然我们可以使用生成器表达式,但我更感兴趣的是看看python在语法方面的可黑客性。对不起,不可能。Dict文本和Dict理解映射到内置的Dict类型,其方式是在C级硬编码的。这是不可推翻的 不过,您可以将其用作备选方案:
OrderedDict((i, i * i) for i in range(3))
附录:从Python 3.6开始,所有Python字典都已订购,它甚至是语言规范的一部分。如果您使用的是那些版本的Python,则无需使用OrderedDict:dict理解将只起作用(TM)。没有直接的方法从语言内部更改Python的语法。字典理解(或普通显示)总是会创建一个
dict
,对此您无能为力。如果您使用的是CPython,那么它使用的是直接生成dict的特殊字节码,dict最终会调用API函数和/或该API使用的相同底层函数。如果您使用的是PyPy,那么这些字节码将在RPythondict
对象上实现,而RPythondict
对象又在编译和优化的Pythondict
上实现。等等
有一种间接的方法,但你不会喜欢的。如果您继续阅读文档,您将看到是导入程序搜索缓存的编译代码或调用编译器,编译器调用解析器,等等。在Python3.3+中,这条链中的几乎所有内容要么是用纯Python编写的,要么有另一个纯Python实现,这意味着您可以分叉代码并做自己的事情。其中包括使用您自己的PyParsing代码解析源代码以构建AST,或将dict CONTRUSION AST节点编译为您自己的自定义字节码而不是默认字节码,或对字节码进行后处理,或 在许多情况下,一个标准就足够了;如果没有,您可以编写一个定制的查找器和加载器 如果您还没有使用Python3.3或更高版本,我强烈建议您在使用这些东西之前进行迁移。在较旧的版本中,这更难,文档也更少,并且最终您将投入10倍的精力来学习在迁移时将过时的东西 无论如何,如果您对这种方法感兴趣,您可能想看看。您可以从中借用一些代码,也许更重要的是,了解其中一些功能(文档中没有好的示例)是如何使用的 或者,如果你愿意接受一些不那么酷的东西,你可以使用
MacroPy
来构建一个“odict理解宏”,并使用它。(请注意,MacroPy目前仅在Python2.7中工作,而不是在3.x中工作。)您无法获得o{…}
,但您可以获得,比如,od[{…}]
,这并不太糟糕。下载、和,然后运行python main.py
查看它的工作情况。关键是这段代码,它接受一个字典comp
AST,将其转换为键值元组上的等效生成器expr
,并将其包装在调用到集合中。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上做黑客加上在运行时挂接的额外工作完全一样。)
如果您想破解,所需的代码位于Python/compile.c
、Python/ceval.c
和Objects/dictobject.c
中,并告诉您如何找到所需的一切。但是你可能想考虑黑客攻击,因为它主要是写在(Python的一个子集而不是C.)中。
顺便说一句,即使一切都是在Python语言级别完成的,您的尝试也不会成功olddict,dict=dict,OrderedDict
在模块的全局中创建名为dict
的绑定,该绑定将名称隐藏在内置项中,但不会替换它。您可以替换内置的东西(好吧,Python不能保证这一点,但是对于我尝试过的每个实现/版本,都有一些特定于实现/版本的东西……),但是您所做的不是这样做的。稍微修改@Max Noel的响应,您可以使用列表理解而不是生成器以有序方式创建OrderedICT(当然,使用dict理解是不可能的)
“我可以扩展语法吗”,你的意思是定制CPython或PyPy之类的东西,还是说fr
>>> OrderedDict([(i, i * i) for i in range(5)])
OrderedDict([(0, 0),
(1, 1),
(2, 4),
(3, 9),
(4, 16)])