属性のように辞書キーにアクセスしますか? 質問する

属性のように辞書キーにアクセスしますか? 質問する

obj.foodict キーに ではなく としてアクセスする方が便利だと思うのでobj['foo']、次のスニペットを書きました:

class AttributeDict(dict):
    def __getattr__(self, attr):
        return self[attr]
    def __setattr__(self, attr, value):
        self[attr] = value

しかし、Python がこの機能を提供していないのには何らかの理由があるはずです。この方法で dict キーにアクセスする場合の注意点や落とし穴は何でしょうか?

ベストアンサー1

アップデート - 2020

この質問が出されたのは約 10 年前ですが、それ以来 Python 自体にはかなりの変化がありました。

私の最初の回答のアプローチは、いくつかのケース(例えば、古いバージョンのPythonに固執しているレガシープロジェクトや、非常に動的な文字列キーを持つ辞書を本当に処理する必要がある場合)では依然として有効ですが、一般的にはデータクラスPython 3.7 で導入された は、 のユースケースの大部分に対する明白な/正しいソリューションですAttrDict

元の回答

これを行う最善の方法は次のとおりです。

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

良い点:

  • 実際に機能します!
  • 辞書クラスのメソッドはシャドウ化されません (たとえば、.keys()問題なく動作します。もちろん、何らかの値を割り当てない限り、以下を参照してください)
  • 属性とアイテムは常に同期されます
  • 存在しないキーを属性としてアクセスしようとすると、AttributeError代わりに次のエラーが発生します。KeyError
  • [Tab]オートコンプリートをサポート(例: jupyter および ipython)

短所:

  • のような方法は、入力データによって上書きされるとうまく機能しなく.keys()なります。
  • 原因メモリーリークPython < 2.7.4 / Python3 < 3.2.3の場合
  • PylintはバナナになりE1123(unexpected-keyword-arg)E1103(maybe-no-member)
  • 初心者にとっては、それは純粋な魔法のように思えます。

これがどのように機能するかについての簡単な説明

  • すべての Python オブジェクトは、 という名前の辞書に属性を内部的に格納します__dict__
  • __dict__内部辞書が「単なる単純な辞書」である必要はないため、dict()内部辞書に の任意のサブクラスを割り当てることができます。
  • 私たちの場合、AttrDict()インスタンス化しているインスタンスを単に割り当てるだけです ( の場合と同様__init__)。
  • super()のメソッドを呼び出すことで、その関数がすべての辞書のインスタンス化コード__init__()を呼び出すため、それが (すでに) 辞書とまったく同じように動作することを確認しました。

Pythonがこの機能を提供しない理由の1つは

「cons」リストに記載されているように、これは格納されたキーの名前空間 (任意のデータや信頼できないデータから取得される可能性があります) と組み込みの dict メソッド属性の名前空間を組み合わせます。例:

d = AttrDict()
d.update({'items':["jacket", "necktie", "trousers"]})
for k, v in d.items():    # TypeError: 'list' object is not callable
    print "Never reached!"

おすすめ記事