要实现你所问的功能,你需要操作文件的语法树。我认为这样做不可取,但是我忍不住想尝试一下。所以我们开始吧。
首先,我们创建一个模块,并在其中定义一个函数my_execfile()
,该函数的工作方式类似于内置的execfile()
函数,但它会将所有字典显示替换为显式调用dict()
构造函数的形式,例如:dict([(3, 4), ('a', 2)])
,而不是像这样:{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
来修改字典显示的行为。以下是一个示例:
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()
构造函数。您需要向DictDisplayTransformer
类添加一个visit_DictComp()
方法。鉴于上面的示例代码,这应该很容易实现。
再次提醒,我不建议这种搞乱语言语义的行为。您看过ConfigParser
模块了吗?
dict
都会保留插入顺序,所以今后将不再需要使用这些技巧。 - Nick SweetingOrderedDict
的唯一方法;popitem
以FIFO模式弹出的能力在dict
上不可用,并且根本不可用move_to_end
(您可以使用mydict[key] = mydict.pop(key)
模拟last=True
模式,但它略微更昂贵,而last=False
模式不可用)。 3.6-3.7还缺少迭代dict
及其视图的能力,尽管3.8(可能)正在添加该功能。 - ShadowRanger