理想的には、私が達成しようとしているのはdict
、Pythonでaを拡張する(または非常に似ている)クラスであり、次の追加機能があります。
- ドット-値の設定と取得が可能な表記
dict
(つまり、setitem、getitem)のようなKey-Value機能- ドット表記の操作を連鎖させることができます
目標は、私がそれexample = DotDict()
に対して次のことを行うことができるようなものを持っていてexample.configuration.first= 'first'
、それが適切なDotDictインスタンスをインスタンス化するexample
場合ですが、操作が割り当てられていない場合は、単純にKeyError
同じように発生させる必要があるという非常に苦痛な警告がdict
あります
これが私が素朴に組み立てたものです
class DotDict(dict):
def __getattr__(self, key):
""" Make attempts to lookup by nonexistent attributes also attempt key lookups. """
import traceback
import re
s= ''.join(traceback.format_stack(sys._getframe(1),1))
if re.match(r' File.*\n.*[a-zA-Z]+\w*\.[a-zA-Z]+[a-zA-Z0-9_. ]*\s*=\s*[a-zA-Z0-9_.\'"]+',s):
self[key] = DotDict()
return self[key]
return self[key]
def __setattr__(self, key, value):
if isinstance(value,dict):
self[key] = DotDict(value)
self[key] = value
いくつかの一般的なエッジケースを除いては機能しますが、私はこの方法が絶対に嫌いであり、より良い方法があるはずです。スタックを見て、最後の行で正規表現を実行することは、これを達成するための良い方法ではありません。
問題の核心は、Pythonがコードの行を左から右に解釈するため、a.b.c = 3
最初の操作がagetattr(a,b)
であり、setattr
そうではないようなステートメントに到達したときに、操作のスタックの最後の操作が割り当てであるかどうかを簡単に判断できないことです。 。
私が知りたいのは、操作のスタックの最後の操作を決定する良い方法があるかどうか、または少なくともそれがであるかどうかsetattr
です。
編集:
これは、user1320237の推奨のおかげで私が思いついた解決策です。
class DotDict(dict):
def __getattr__(self, key):
""" Make attempts to lookup by nonexistent attributes also attempt key lookups. """
if self.has_key(key):
return self[key]
import sys
import dis
frame = sys._getframe(1)
if '\x00%c' % dis.opmap['STORE_ATTR'] in frame.f_code.co_code:
self[key] = DotDict()
return self[key]
raise AttributeError('Problem here')
def __setattr__(self, key, value):
if isinstance(value,dict):
self[key] = DotDict(value)
self[key] = value
実際の実装にはもう少しありますが、それは素晴らしい仕事をします。それが機能する方法は、スタックの最後のフレームを検査し、バイトコードでSTORE_ATTR操作をチェックすることです。これは、実行されている操作がa.b.this.doesnt.exist.yet = 'something'
説得力があることを意味します。これがCPython以外の他のインタープリターで実行できるかどうか知りたいです。