覆盖 {...} 符号,以便我得到 OrderedDict() 而不是 dict()?

发布于 2024-12-11 18:46:59 字数 619 浏览 7 评论 0 原文

更新:Python 3.7+ 保证保留插入顺序的字典

我想使用像配置文件一样的 .py 文件。 因此,使用 {...} 表示法,我可以使用字符串作为键创建一个字典,但定义顺序在标准 python 字典中丢失了。

我的问题:是否可以覆盖 {...} 表示法,以便我得到 OrderedDict() 而不是 dict()

我希望简单地用 OrderedDict (dict = OrderedDict) 覆盖 dict 构造函数就可以工作,但事实并非如此。

例如:

dict = OrderedDict
dictname = {
   'B key': 'value1',
   'A key': 'value2',
   'C key': 'value3'
   }

print dictname.items()

输出:

[('B key', 'value1'), ('A key', 'value2'), ('C key', 'value3')]

Update: dicts retaining insertion order is guaranteed for Python 3.7+

I want to use a .py file like a config file.
So using the {...} notation I can create a dictionary using strings as keys but the definition order is lost in a standard python dictionary.

My question: is it possible to override the {...} notation so that I get an OrderedDict() instead of a dict()?

I was hoping that simply overriding dict constructor with OrderedDict (dict = OrderedDict) would work, but it doesn't.

Eg:

dict = OrderedDict
dictname = {
   'B key': 'value1',
   'A key': 'value2',
   'C key': 'value3'
   }

print dictname.items()

Output:

[('B key', 'value1'), ('A key', 'value2'), ('C key', 'value3')]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

遗心遗梦遗幸福 2024-12-18 18:46:59

这是一个几乎可以为您提供所需语法的黑客:

class _OrderedDictMaker(object):
    def __getitem__(self, keys):
        if not isinstance(keys, tuple):
            keys = (keys,)
        assert all(isinstance(key, slice) for key in keys)

        return OrderedDict([(k.start, k.stop) for k in keys])

ordereddict = _OrderedDictMaker()
from nastyhacks import ordereddict

menu = ordereddict[
   "about" : "about",
   "login" : "login",
   'signup': "signup"
]

编辑:其他人独立发现了这一点,并发布了odictliteral 包提供了稍微更彻底的实现 - 改用该包

Here's a hack that almost gives you the syntax you want:

class _OrderedDictMaker(object):
    def __getitem__(self, keys):
        if not isinstance(keys, tuple):
            keys = (keys,)
        assert all(isinstance(key, slice) for key in keys)

        return OrderedDict([(k.start, k.stop) for k in keys])

ordereddict = _OrderedDictMaker()
from nastyhacks import ordereddict

menu = ordereddict[
   "about" : "about",
   "login" : "login",
   'signup': "signup"
]

Edit: Someone else discovered this independently, and has published the odictliteral package on PyPI that provides a slightly more thorough implementation - use that package instead

孤星 2024-12-18 18:46:59

要真正获得您所要求的内容,您必须摆弄文件的语法树。我认为这样做并不可取,但我无法抗拒尝试的诱惑。那么我们开始吧。

首先,我们创建一个带有函数 my_execfile() 的模块,其工作方式与内置 execfile() 类似,只是显示所有出现的字典,例如 { 3: 4, "a": 2} 被显式调用 dict() 构造函数替换,例如 dict([(3, 4), ('a' , 2)])。 (当然,我们可以通过调用 collections.OrderedDict() 来直接替换它们,但我们不想太干扰。)代码如下:

import ast

class DictDisplayTransformer(ast.NodeTransformer):
    def visit_Dict(self, node):
        self.generic_visit(node)
        list_node = ast.List(
            [ast.copy_location(ast.Tuple(list(x), ast.Load()), x[0])
             for x in zip(node.keys, node.values)],
            ast.Load())
        name_node = ast.Name("dict", ast.Load())
        new_node = ast.Call(ast.copy_location(name_node, node),
                            [ast.copy_location(list_node, node)],
                            [], None, None)
        return ast.copy_location(new_node, node)

def my_execfile(filename, globals=None, locals=None):
    if globals is None:
        globals = {}
    if locals is None:
        locals = globals
    node = ast.parse(open(filename).read())
    transformed = DictDisplayTransformer().visit(node)
    exec compile(transformed, filename, "exec") in globals, locals

进行此修改后,我们可以通过覆盖dict来修改字典显示的行为。下面是一个示例:

# test.py
from collections import OrderedDict
print {3: 4, "a": 2}
dict = OrderedDict
print {3: 4, "a": 2}

现在我们可以使用 my_execfile("test.py") 运行此文件,生成输出

{'a': 2, 3: 4}
OrderedDict([(3, 4), ('a', 2)])

请注意,为了简单起见,上面的代码不涉及字典推导式,应该对其进行转换传递给 dict() 构造函数的生成器表达式。您需要将 visit_DictComp() 方法添加到 DictDisplayTransformer 类中。鉴于上面的示例代码,这应该是简单的。

再次强调,我不建议这种对语言语义的混乱。您查看过 ConfigParser 模块吗?

To literally get what you are asking for, you have to fiddle with the syntax tree of your file. I don't think it is advisable to do so, but I couldn't resist the temptation to try. So here we go.

First, we create a module with a function my_execfile() that works like the built-in execfile(), except that all occurrences of dictionary displays, e.g. {3: 4, "a": 2} are replaced by explicit calls to the dict() constructor, e.g. dict([(3, 4), ('a', 2)]). (Of course we could directly replace them by calls to collections.OrderedDict(), but we don't want to be too intrusive.) Here's the code:

import ast

class DictDisplayTransformer(ast.NodeTransformer):
    def visit_Dict(self, node):
        self.generic_visit(node)
        list_node = ast.List(
            [ast.copy_location(ast.Tuple(list(x), ast.Load()), x[0])
             for x in zip(node.keys, node.values)],
            ast.Load())
        name_node = ast.Name("dict", ast.Load())
        new_node = ast.Call(ast.copy_location(name_node, node),
                            [ast.copy_location(list_node, node)],
                            [], None, None)
        return ast.copy_location(new_node, node)

def my_execfile(filename, globals=None, locals=None):
    if globals is None:
        globals = {}
    if locals is None:
        locals = globals
    node = ast.parse(open(filename).read())
    transformed = DictDisplayTransformer().visit(node)
    exec compile(transformed, filename, "exec") in globals, locals

With this modification in place, we can modify the behaviour of dictionary displays by overwriting dict. Here is an example:

# test.py
from collections import OrderedDict
print {3: 4, "a": 2}
dict = OrderedDict
print {3: 4, "a": 2}

Now we can run this file using my_execfile("test.py"), yielding the output

{'a': 2, 3: 4}
OrderedDict([(3, 4), ('a', 2)])

Note that for simplicity, the above code doesn't touch dictionary comprehensions, which should be transformed to generator expressions passed to the dict() constructor. You'd need to add a visit_DictComp() method to the DictDisplayTransformer class. Given the above example code, this should be straight-forward.

Again, I don't recommend this kind of messing around with the language semantics. Did you have a look into the ConfigParser module?

怀里藏娇 2024-12-18 18:46:59

OrderedDict 不是“标准 python 语法”,但是,一组有序的键值对(采用标准 python 语法)很简单:

[('key1 name', 'value1'), ('key2 name', 'value2'), ('key3 name', 'value3')]

要显式获取 OrderedDict

OrderedDict([('key1 name', 'value1'), ('key2 name', 'value2'), ('key3 name', 'value3')])

另一种选择,是对 dictname.items() 进行排序,如果这就是您所需要的:

sorted(dictname.items())

OrderedDict is not "standard python syntax", however, an ordered set of key-value pairs (in standard python syntax) is simply:

[('key1 name', 'value1'), ('key2 name', 'value2'), ('key3 name', 'value3')]

To explicitly get an OrderedDict:

OrderedDict([('key1 name', 'value1'), ('key2 name', 'value2'), ('key3 name', 'value3')])

Another alternative, is to sort dictname.items(), if that's all you need:

sorted(dictname.items())
情何以堪。 2024-12-18 18:46:59

从 python 3.6 开始,所有字典将按以下顺序排序默认

插入顺序始终保留在新的 dict 实现中:

>>>x = {'a': 1, 'b':2, 'c':3 }
>>>list(x.keys())
['a', 'b', 'c']

从 python 3.6 **kwargs 顺序 [PEP468] 和类属性顺序 [PEP520] 被保留。新的紧凑、有序的字典实现 用于实现这两者的排序。

As of python 3.6, all dictionaries will be ordered by default.

Insertion order is always preserved in the new dict implementation:

>>>x = {'a': 1, 'b':2, 'c':3 }
>>>list(x.keys())
['a', 'b', 'c']

As of python 3.6 **kwargs order [PEP468] and class attribute order [PEP520] are preserved. The new compact, ordered dictionary implementation is used to implement the ordering for both of these.

揽月 2024-12-18 18:46:59

你所要求的是不可能的,但如果 JSON 语法中的配置文件就足够了,你可以做一些事情与 json 模块类似 :

>>> import json, collections
>>> d = json.JSONDecoder(object_pairs_hook = collections.OrderedDict)
>>> d.decode('{"a":5,"b":6}')
OrderedDict([(u'a', 5), (u'b', 6)])

What you are asking for is impossible, but if a config file in JSON syntax is sufficient you can do something similar with the json module:

>>> import json, collections
>>> d = json.JSONDecoder(object_pairs_hook = collections.OrderedDict)
>>> d.decode('{"a":5,"b":6}')
OrderedDict([(u'a', 5), (u'b', 6)])
送君千里 2024-12-18 18:46:59

我找到的一个解决方案是修补 python 本身,使 dict 对象记住插入的顺序。

这适用于所有类型的语法:

x = {'a': 1, 'b':2, 'c':3 }
y = dict(a=1, b=2, c=3)

等等。

我从 ordereddict C 实现“noreferrer">https://pypi.python.org/pypi/ruamel.ordereddict/ 并合并回主 python 代码中。

如果您不介意重新构建 python 解释器,这里有一个 Python 2.7.8 的补丁:
https://github.com/fwyzard/cpython /compare/2.7.8...ordereddict-2.7.8.diff
。一个

The one solution I found is to patch python itself, making the dict object remember the order of insertion.

This then works for all kind of syntaxes:

x = {'a': 1, 'b':2, 'c':3 }
y = dict(a=1, b=2, c=3)

etc.

I have taken the ordereddict C implementation from https://pypi.python.org/pypi/ruamel.ordereddict/ and merged back into the main python code.

If you do not mind re-building the python interpreter, here is a patch for Python 2.7.8:
https://github.com/fwyzard/cpython/compare/2.7.8...ordereddict-2.7.8.diff
.A

写下不归期 2024-12-18 18:46:59

如果您正在寻找一种获得易于使用的初始化语法的方法 - 考虑创建 OrderedDict 的子类并向其添加更新字典的运算符,例如:

from collections import OrderedDict

class OrderedMap(OrderedDict):
    def __add__(self,other):
        self.update(other)
        return self

d = OrderedMap()+{1:2}+{4:3}+{"key":"value"}

d will be- OrderedMap([(1, 2) , (4, 3), ('key','value')])


使用切片语法的另一个可能的语法糖示例:

class OrderedMap(OrderedDict):
    def __getitem__(self, index):
        if isinstance(index, slice):
            self[index.start] = index.stop 
            return self
        else:
            return OrderedDict.__getitem__(self, index)

d = OrderedMap()[1:2][6:4][4:7]["a":"H"]

If what you are looking for is a way to get easy-to-use initialization syntax - consider creating a subclass of OrderedDict and adding operators to it that update the dict, for example:

from collections import OrderedDict

class OrderedMap(OrderedDict):
    def __add__(self,other):
        self.update(other)
        return self

d = OrderedMap()+{1:2}+{4:3}+{"key":"value"}

d will be- OrderedMap([(1, 2), (4, 3), ('key','value')])


Another possible syntactic-sugar example using the slicing syntax:

class OrderedMap(OrderedDict):
    def __getitem__(self, index):
        if isinstance(index, slice):
            self[index.start] = index.stop 
            return self
        else:
            return OrderedDict.__getitem__(self, index)

d = OrderedMap()[1:2][6:4][4:7]["a":"H"]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文