41

更新:Python3.7以降では挿入順序を保持するdictが保証されています

設定ファイルのような.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')]
4

7 に答える 7

78

これが、必要な構文をほぼ提供するハックです。

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で公開しました-代わりにそのパッケージを使用してください

于 2016-05-16T17:38:52.293 に答える
40

文字通りあなたが求めているものを手に入れるために、あなたはあなたのファイルの構文木をいじる必要があります。そうすることはお勧めできないと思いますが、試してみたいという誘惑に抵抗することはできませんでした。だからここに行きます。

最初に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モジュールを調べましたか?

于 2011-10-24T18:43:56.373 に答える
13

OrderedDictは「標準のPython構文」ではありませんが、(標準のPython構文の)キーと値のペアの順序付けられたセットは単純です。

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

明示的に取得するにはOrderedDict

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

もう1つの方法は、dictname.items()必要なのがそれだけの場合は、並べ替えることです。

sorted(dictname.items())
于 2011-10-24T16:51:04.173 に答える
6

Python 3.6以降、すべての辞書はデフォルトで順序付けられます。今のところ、これはの実装の詳細でdictあり、信頼すべきではありませんが、v3.6以降は標準になる可能性があります。

dict新しい実装では、挿入順序は常に保持されます。

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

Python 3.6以降、**kwargs順序[PEP468]とクラス属性の順序[ PEP520 ]は保持されます。新しいコンパクトで順序付けられた辞書の実装は、これらの両方の順序付けを実装するために使用されます。

于 2016-12-17T04:35:29.467 に答える
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)])
于 2011-10-24T18:04:58.607 に答える
5

私が見つけた1つの解決策は、Python自体にパッチを適用し、dictオブジェクトに挿入の順序を記憶させることです。

これは、あらゆる種類の構文で機能します。

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コードにマージして戻しました。

Pythonインタープリターを再構築してもかまわない場合は、Python 2.7.8のパッチを次に示します: https ://github.com/fwyzard/cpython/compare/2.7.8...ordereddict-2.7.8.diff 。 A

于 2014-12-03T11:30:45.087 に答える
0

探しているのが使いやすい初期化構文を取得する方法である場合は、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は次のようになります-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"]
于 2014-09-17T11:25:27.747 に答える