OrderedDict理解 [英] OrderedDict comprehensions

查看:112
本文介绍了OrderedDict理解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以在python中扩展语法以获取其他dict的dict理解力吗,例如collections模块中的OrderedDict还是我自己的从dict继承的类型?

Can I extend syntax in python for dict comprehensions for other dicts, like the OrderedDict in collections module or my own types which inherit from dict?

仅重新绑定dict名称显然是行不通的,{key: value}理解语法仍然为您提供了理解和文字的普通用法.

Just rebinding the dict name obviously doesn't work, the {key: value} comprehension syntax still gives you a plain old dict for comprehensions and literals.

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

那么,如果可能的话,我将如何去做呢?如果它仅适用于CPython,就可以了.对于语法,我想我会像在r'various' u'string' b'objects'上那样使用O{k: v}前缀进行尝试.

So, if it's possible how would I go about doing that? It's OK if it only works in CPython. For syntax I guess I would try it with a O{k: v} prefix like we have on the r'various' u'string' b'objects'.

注意:当然,我们可以改用生成器表达式,但是我更感兴趣的是从语法角度看python的可破解性.

note: Of course we can use a generator expression instead, but I'm more interested seeing how hackable python is in terms of the grammar.

推荐答案

没有直接方法可以从语言中更改Python的语法.字典理解(或普通显示)总是会创建dict,您对此无能为力.如果您使用的是CPython,它将使用特殊的字节码直接生成dict,最终会调用

There is no direct way to change Python's syntax from within the language. A dictionary comprehension (or plain display) is always going to create a dict, and there's nothing you can do about that. If you're using CPython, it's using special bytecodes that generate a dict directly, which ultimately call the PyDict API functions and/or the same underlying functions used by that API. If you're using PyPy, those bytecodes are instead implemented on top of an RPython dict object which in turn is implemented on top of a compiled-and-optimized Python dict. And so on.

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

There is an indirect way to do it, but you're not going to like it. If you read the docs on the import system, you'll see that it's the importer that searches for cached compiled code or calls the compiler, and the compiler that calls the parser, and so on. In Python 3.3+, almost everything in this chain either is written in pure Python, or has an alternate pure Python implementation, meaning you can fork the code and do your own thing. Which includes parsing source with your own PyParsing code that builds ASTs, or compiling a dict comprehension AST node into your own custom bytecode instead of the default, or post-processing the bytecode, or…

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

In many cases, an import hook is sufficient; if not, you can always write a custom finder and loader.

如果您尚未使用Python 3.3或更高版本,我强烈建议您在使用这些东西之前先进行迁移.在较旧的版本中,它变得更困难,文档也更少,最终您将付出10倍的精力来学习一些在每次迁移时都会过时的东西.

If you're not already using Python 3.3 or later, I'd strongly suggest migrating before playing with this stuff. In older versions, it's harder, and less well documented, and you'll ultimately be putting in 10x the effort to learn something that will be obsolete whenever you do migrate.

无论如何,如果您觉得这种方法很有趣,您可能想看看 MacroPy .您可以从中借用一些代码,也许更重要的是,了解如何使用其中的某些功能(在文档中没有好的示例).

Anyway, if this approach sounds interesting to you, you might want to take a look at MacroPy. You could borrow some code from it—and, maybe more importantly, learn how some of these features (that have no good examples in the docs) are used.

或者,如果您愿意接受一些不太酷的东西,则可以使用MacroPy来构建命令理解宏"并使用它. (请注意,MacroPy当前仅在Python 2.7中可用,而不在3.x中可用.)您可能不太了解o{…},但可以获取例如od[{…}],这还不错.下载 od.py realmain.py main.py ,然后运行python main.py使其正常运行.关键是此代码,该代码采用DictionaryComp AST,将其转换为键值Tuple s上的等效GeneratorExpr,并将其包装在Callcollections.OrderedDict中:

Or, if you're willing to settle for something less cool, you can just use MacroPy to build an "odict comprehension macro" and use that. (Note that MacroPy currently only works in Python 2.7, not 3.x.) You can't quite get o{…}, but you can get, say, od[{…}], which isn't too bad. Download od.py, realmain.py, and main.py, and run python main.py to see it working. The key is this code, which takes a DictionaryComp AST, converts it to an equivalent GeneratorExpr on key-value Tuples, and wraps it in a Call to 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解释器.


A different alternative is, of course, to modify the Python interpreter.

我建议您一开始就放弃O{…}语法的想法,而只是将普通的dict理解编译为o令.好消息是,您实际上不需要更改语法(这超出了毛发……),只需更改以下任何一项即可:

I would suggest dropping the O{…} syntax idea for your first go, and just making normal dict comprehensions compile to odicts. The good news is, you don't really need to change the grammar (which is beyond hairy…), just any one of:

  • dictcomps编译到的字节码
  • 解释器运行这些字节码的方式,或者
  • PyDict类型的实现
  • the bytecodes that dictcomps compile to,
  • the way the interpreter runs those bytecodes, or
  • the implementation of the PyDict type

坏消息是,尽管所有这些都比更改语法容易得多,但扩展模块无法完成所有这些工作. (好吧,您可以通过执行与纯Python基本上相同的操作来做第一个……并且您可以通过将.so/.dll/.dylib挂钩来修补自己的函数来完成其中的任何一个操作,但这就是与在Python上进行黑客攻击完全相同,再加上在运行时进行钩子的额外工作.)

The bad news, while all of those are a lot easier than changing the grammar, none of them can be done from an extension module. (Well, you can do the first one by doing basically the same thing you'd do from pure Python… and you can do any of them by hooking the .so/.dll/.dylib to patch in your own functions, but that's the exact same work as hacking on Python plus the extra work of hooking at runtime.)

如果您想入侵 CPython源,则所需的代码位于Python/ceval.cObjects/dictobject.c,以及开发指南告诉您如何查找所有内容需要.但是您可能要考虑使用 PyPy源进行黑客攻击,因为它主要是用( ),而不是C.

If you want to hack on CPython source, the code you want is in Python/compile.c, Python/ceval.c, and Objects/dictobject.c, and the dev guide tells you how to find everything you need. But you might want to consider hacking on PyPy source instead, since it's mostly written in (a subset of) Python rather than C.

请注意,即使一切都在Python语言级别完成,您的尝试也不会奏效. olddict, dict = dict, OrderedDict在模块的全局变量中创建一个名为dict的绑定,该绑定阴影内置函数中的名称,但不会替换它.您可以 替换内置函数中的内容(嗯,Python不能保证这一点,但是我尝试过的每种实现/版本都具有特定于实现/版本的东西…… ),但您做不到的方式.

As a side note, your attempt wouldn't have worked even if everything were done at the Python language level. olddict, dict = dict, OrderedDict creates a binding named dict in your module's globals, which shadows the name in builtins, but doesn't replace it. You can replace things in builtins (well, Python doesn't guarantee this, but there are implementation/version-specific things-that-happen-to-work for every implementation/version I've tried…), but what you did isn't the way to do it.

这篇关于OrderedDict理解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆