我是否可以扩展python中的语法,以便对其他dict进行理解,比如OrderedDict in collections模块或我自己的继承自dict的类型?
重新绑定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'上使用的那样。
注意:当然,我们可以使用生成器表达式,但我更感兴趣的是,从语法的角度来看,python是多么容易被黑客攻击。
发布于 2014-01-14 00:09:24
没有从语言内部直接更改Python语法的方法。字典理解(或普通显示)总是会创建一个dict,对此您无能为力。如果您使用的是CPython,那么它使用的是专门的字节码,它直接生成dict,最终调用PyDict API函数和/或该API使用的相同的底层函数。如果使用PyPy,则这些字节码是在RPython dict对象之上实现的,而后者又是在编译和优化的Python dict之上实现的。诸若此类。
有一种间接的方法,但你不会喜欢的。如果在进口制度上读取文档,您将看到是导入器搜索缓存的编译代码或调用编译器,以及编译器调用解析器,等等。在Python中,这个链中的几乎所有东西都是用纯3.3+编写的,或者有一个替代的纯Python实现,这意味着您可以分叉代码并完成自己的工作。它包括用自己构建AST的PyParsing代码解析源代码,或者将dict解译AST节点编译到您自己的自定义字节码中,而不是默认的字节码,或者对字节码进行后处理,或…。
在许多情况下,进口钩就足够了;如果不是,您可以始终编写自定义查找器和加载程序。
如果您还没有使用Python3.3或更高版本,我强烈建议在使用这些东西之前进行迁移。在旧版本中,这很难,而且文档也不那么清楚,最终您将投入10倍的精力去学习那些一旦迁移就会过时的东西。
无论如何,如果这个方法听起来很有趣,那么您可能想看看MacroPy。您可以从其中借用一些代码--也许更重要的是,学习如何使用这些特性(在文档中没有好的示例)。
或者,如果你愿意接受一些不那么酷的东西,你可以使用MacroPy构建一个“有条不紊的理解宏”并使用它。(请注意,MacroPy目前只使用Python2.7,而不是3.x)。你不能完全得到o{…},但你可以得到,比方说,od[{…}],这还不算太糟。下载od.py、realmain.py和main.py,并运行python main.py以确保其正常工作。关键是以下代码,它接受DictionaryComp AST,将其转换为键值Tuples上的等效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当然,另一个不同的选择是修改Python解释器。
我建议您在第一次尝试时放弃O{…}语法的想法,而只是将普通的dict理解编译成系统。好消息是,您不需要真正改变语法(这超出了多毛的…),只是以下任何一种:
PyDict类型的实现坏消息是,虽然所有这些都比修改语法容易得多,但它们都不能通过扩展模块完成。(好吧,你可以做第一件事,基本上和你用纯Python做的事情一样您可以通过将. to /..dll/..dylib连接到您自己的函数中来实现其中的任何一个,但这与在Python上进行黑客攻击以及在运行时挂钩的额外工作完全相同。)
如果您想黑CPython源,您想要的代码是在Python/compile.c、Python/ceval.c和Objects/dictobject.c中,发展指南告诉您如何找到所需的一切。但是您可能需要考虑对PyPy源进行黑客攻击,因为它大多是用Python的子集编写的,而不是用C编写的。
顺便提一句,即使在Python语言级别完成了所有工作,您的尝试也不会奏效。olddict, dict = dict, OrderedDict在模块的全局文件中创建一个名为dict的绑定,该绑定将名称隐藏在内置文件中,但不会替换它。您可以在内置程序中替换东西(好吧,Python不能保证这一点,但是对于我尝试过的每一个…实现/版本,都有特定于实现/版本的事情-可能发生的事情)但你所做的并不是解决问题的方法。
发布于 2014-01-14 00:03:03
抱歉,不可能。Dict文字和dict理解映射到内置的dict类型,其方式是在C级别硬编码。那是不能被推翻的。
不过,您可以将此用作替代方法:
OrderedDict((i, i * i) for i in range(3))增编:从Python3.6开始,所有的Python字典都被订购了。截至3.7,它甚至是语言规范的一部分。如果您正在使用那些版本的Python,则不需要使用OrderedDict: dict理解将只起作用(TM)。
发布于 2015-04-28 21:16:14
稍微修改@Max的响应,您可以使用列表理解(而不是生成器)以有序的方式创建OrderedDict (当然,使用dict理解是不可能的)。
>>> OrderedDict([(i, i * i) for i in range(5)])
OrderedDict([(0, 0),
(1, 1),
(2, 4),
(3, 9),
(4, 16)])https://stackoverflow.com/questions/21103732
复制相似问题