覆盖{…}符号,所以我得到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。