覆盖{...}符号所以我得到一个OrderedDict()而不是一个dict()?

fdb*_*fdb 41 python dictionary overriding ordereddictionary built-in

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

我的问题:是否有可能覆盖{...}符号,以便我得到一个OrderedDict()而不是dict()

我希望用OrderedDict(dict = OrderedDict)简单地覆盖dict构造函数会起作用,但事实并非如此.

例如:

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

print dictname.items()
Run Code Online (Sandbox Code Playgroud)

输出:

[('B key', 'value1'), ('A key', 'value2'), ('C key', 'value3')]
Run Code Online (Sandbox Code Playgroud)

Eri*_*ric 77

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

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()
Run Code Online (Sandbox Code Playgroud)
from nastyhacks import ordereddict

menu = ordereddict[
   "about" : "about",
   "login" : "login",
   'signup': "signup"
]
Run Code Online (Sandbox Code Playgroud)

编辑:其他人独立发现了这个,并odictliteral在PyPI 上发布了一个包,它提供了一个稍微更全面的实现 - 请改用它

  • 这是天才.邪恶的天才. (11认同)
  • @Eric我来自reddit https://www.reddit.com/r/Python/comments/4xyfh7/one_of_the_neatest_python_tricks_ive_ever_seen/?st=irxxcanz&sh=a6b172af (4认同)
  • 要帮助解释其工作原理,请参阅http://stackoverflow.com/questions/2936863/python-implementing-slicing-in-getitem (3认同)
  • 不寒而栗 - 我明白你为什么称之为黑客 - 请 - 不要在生产中使用它 (2认同)

Sve*_*ach 39

要真正得到你要求的东西,你必须摆弄文件的语法树.我不认为这样做是可取的,但我无法抗拒尝试的诱惑.所以我们走了.

首先,我们创建一个具有与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
Run Code Online (Sandbox Code Playgroud)

通过这种修改,我们可以通过覆盖修改字典显示的行为dict.这是一个例子:

# test.py
from collections import OrderedDict
print {3: 4, "a": 2}
dict = OrderedDict
print {3: 4, "a": 2}
Run Code Online (Sandbox Code Playgroud)

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

{'a': 2, 3: 4}
OrderedDict([(3, 4), ('a', 2)])
Run Code Online (Sandbox Code Playgroud)

请注意,为简单起见,上面的代码不接触字典理解,字典理解应转换为传递给dict()构造函数的生成器表达式.您需要向该类添加visit_DictComp()方法DictDisplayTransformer.鉴于上面的示例代码,这应该是直截了当的.

同样,我不推荐这种语言语义的混乱.你有没看过这个ConfigParser模块?

  • 是的我将使用ConfigParser ...但你的解决方案很有启发性.非常感谢你. (3认同)
  • @fdb - 在你想到改变语言语义之前 - 考虑一下'明确比隐含更好'的原则 - 如果你试图覆盖'{}'或者隐藏以避免输入'OrderedDict' - 你将最终制作你的对于其他人而言,代码更难以阅读 - 对于你自己来说,6个月之后.只需键入'OrderedDict' - 它就可以理解,并做你想要的 - 更多的打字,但提高了可读性. (3认同)

Aus*_*all 13

OrderedDict 不是"标准python语法",但是,一组有序的键值对(在标准python语法中)就是:

[('key1 name', 'value1'), ('key2 name', 'value2'), ('key3 name', 'value3')]
Run Code Online (Sandbox Code Playgroud)

要明确获得OrderedDict:

OrderedDict([('key1 name', 'value1'), ('key2 name', 'value2'), ('key3 name', 'value3')])
Run Code Online (Sandbox Code Playgroud)

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

sorted(dictname.items())
Run Code Online (Sandbox Code Playgroud)

  • 我的问题是,如果OrderedDict是"标准python语法",但是如果可以覆盖{...}表示法 (5认同)
  • @fdb:在Python` {}中创建一个`dict`对象,它按定义无序.您当然可以用`{}'来定义自己的语言,表示一个有序的字典.您甚至可以编写一个将新语言翻译为Python的小包装器.这是你真正想要的吗? (3认同)
  • @SvenMarnach:是的!但希望简单地用OrderedDict(dict = OrderedDict)重写dict构造函数就行了. (2认同)
  • @fdb:只有通过调用`dict()`创建字典才有效 (2认同)

Nic*_*ing 6

从 python 3.6 开始,所有字典都将默认排序。目前,这是一个实现细节,dict不应依赖,但它可能会在 v3.6 之后成为标准。

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

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

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

  • 更新:被保留的插入顺序现在是 3.7 的标准并且可以依赖。 (2认同)

Mag*_*off 5

您要求的是不可能的,但如果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)])
Run Code Online (Sandbox Code Playgroud)

  • "不可能"可能有点过于强烈 - 请参阅我的回答. (9认同)
  • @Sven:是的,我非常喜欢你的回答!:)但我想我会让我的措辞成立.请在此背景下调整您对"不可能"的理解以匹配现实;) (2认同)

fwy*_*ard 5

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

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

x = {'a': 1, 'b':2, 'c':3 }
y = dict(a=1, b=2, c=3)
Run Code Online (Sandbox Code Playgroud)

等等。

ordereddicthttps://pypi.python.org/pypi/ruamel.ordereddict/获取了C 实现并合并回了主要的 python 代码。

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

  • 从 2016/12 开始,Pypy 实现将成为标准的 Python `dict` 实现,提前 2 年预测得很好! (2认同)