覆盖{…}符号,所以我得到OrderedDict()而不是一个字典()?

我想用一个.py文件,像一个configuration文件。 所以使用{...}符号我可以创build一个字典作为键的字典,但定义顺序是在标准的Python字典中丢失。

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

我希望简单地重写OrderedDict( dict = OrderedDict )的字典构造函数将工作,但它不。

例如:

 dict = OrderedDict dictname = { 'B key': 'value1', 'A key': 'value2', 'C key': 'value3' } print dictname.items() 

输出:

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

要从字面上得到你所要求的,你必须摆弄你的文件的语法树。 我不认为这样做是可取的,但是我无法抗拒尝试的诱惑。 所以我们走了

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

 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)]) 

请注意,为了简单起见,上面的代码不会触及字典parsing,应将其转换为传递给dict()构造函数的生成器expression式。 您需要将一个visit_DictComp()方法添加到DictDisplayTransformer类。 鉴于上面的示例代码,这应该是直截了当的。

再次,我不推荐这种与语言语义混杂的东西。 你有没有看过ConfigParser模块?

这里几乎给你你想要的语法:

 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包PyPI,提供了一个稍微更彻底的实现

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()进行sorting,如果这就是你所需要的:

 sorted(dictname.items()) 

你所要求的是不可能的,但是如果一个JSON语法的configuration文件是足够的,你可以做类似的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)]) 

我find的一个解决scheme是修补Python本身,使dict对象记住插入的顺序。

然后这适用于所有types的语法:

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

等等

我已经从https://pypi.python.org/pypi/ruamel.ordereddict/采取了;ordereddict C实现,并合并回到主python代码。

如果你不介意重新构buildpython解释器,下面是Python 2.7.8的补丁: https : //github.com/fwyzard/cpython/compare/2.7.8…ordereddict-2.7.8.diff 。一个

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

 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将被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"] 

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

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

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

从python 3.6 **kwargs命令[PEP468]和类属性命令[ PEP520 ]被保留。 新的紧凑,有序的字典实现被用来实现这两者的sorting。