web-dev-qa-db-ja.com

{...}表記をオーバーライドして、dict()ではなくOrderedDict()を取得しますか?

設定ファイルのような.pyファイルを使用したい。したがって、_{...}_表記を使用して、文字列をキーとして使用して辞書を作成できますが、標準のpython辞書では定義の順序が失われます。

私の質問:_{...}_表記をオーバーライドして、OrderedDict()の代わりにdict()を取得することは可能ですか?

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')]
_
41
fdb

ここにあなたが望む構文をほぼ与えるハックがあります:

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で公開しましたより完全な実装-代わりにそのパッケージを使用します

77
Eric

文字通り求めているものを取得するには、ファイルの構文ツリーをいじる必要があります。私はそうすることはお勧めできないと思いますが、私はしようとする誘惑に抵抗できませんでした。さあ、行きます。

まず、組み込みの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
_

この変更を適切に行うと、_candictを上書きして、辞書表示の動作を変更します。次に例を示します。

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

39
Sven Marnach

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())
_
13
Austin Marshall

あなたが求めていることは不可能ですが、 [〜#〜] 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)])
5
Magnus Hoff

python 3.6、 すべての辞書はデフォルトでorderedになります です。現時点では、これはdictの実装の詳細であり、信頼すべきではありませんが、v3.6以降では標準になる可能性があります。

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

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

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

4
Nick Sweeting

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

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

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

等.

ordereddict Cの実装を https://pypi.python.org/pypi/ruamel.ordereddict/ から取得し、メインのpythonコードにマージして戻しました。

pythonインタープリターの再構築を気にしない場合は、Python 2.7.8のパッチを以下に示します。 https://github.com/fwyzard/cpython/compare/2.7。 8 ... ordereddict-2.7.8.diff .A

4
fwyzard

探しているものが使いやすい初期化構文を取得する方法である場合、OrderedDictのサブクラスを作成し、dictを更新する演算子を追加することを検討してください。次に例を示します。

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')])になります


スライス構文を使用した、もう1つの可能な構文糖の例:

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"]
0
Or Weis