Python __setattr__および__getattr__グローバルスコープ用?
-
27-09-2019 - |
質問
Pythonを使用して特定のデータ構造を説明する独自の小さなDSLを作成する必要があると仮定します。たとえば、私は次のようなものを書きたいと思っています
f(x) = some_stuff(a,b,c)
また、pythonを使用して、宣言されていない識別子について不平を言ったり、関数をsome_stuffを呼び出したりしようとする代わりに、それを私のさらなる利便性のために文字通りの表現に変換します。
適切に再定義されたクラスを作成することにより、これに合理的な近似値を取得することができます __getattr__
と __setattr__
方法とそれを次のように使用します:
e = Expression()
e.f[e.x] = e.some_stuff(e.a, e.b, e.c)
迷惑な「e」を取り除くことができれば、それはクールでしょう。プレフィックス、そしておそらく[]の使用を避けることさえあります。それで、私は疑問に思っていました、何らかの形で一時的にグローバル名の検索と割り当てを「再定義」することは可能ですか?関連するメモでは、Python式の「引用」機能を簡単に達成するための良いパッケージがあるかもしれません。
解決
良い考えかどうかはわかりませんが、私は思ったと思います 試してみる. 。要約する:
class PermissiveDict(dict):
default = None
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
return self.default
def exec_with_default(code, default=None):
ns = PermissiveDict()
ns.default = default
exec code in ns
return ns
他のヒント
あなたはを見てみたいかもしれません ast
また parser
Pythonに含まれるモジュールは、入力コードの抽象的な構文ツリー(またはそれぞれ解析ツリー)を解析、アクセス、変換します。私の知る限り、 セージ数学システム, 、Pythonで書かれていると、同様の種類のプレキャコンパイラがあります。
Waiのコメントに応えて、私が見つけた楽しいソリューションの1つがあります。まず第一に、それが何をするかをもう一度説明するために、次のコードがあると仮定します。
definitions = Structure()
definitions.add_definition('f[x]', 'x*2')
definitions.add_definition('f[z]', 'some_function(z)')
definitions.add_definition('g.i', 'some_object[i].method(param=value)')
定義を追加すると、左側と右側を解析し、他の醜いことをすることを意味します。ここで1つ(必ずしも良いわけではありませんが、確かに楽しい)ここでアプローチは、上記のコードを次のように書くことができます。
@my_dsl
def definitions():
f[x] = x*2
f[z] = some_function(z)
g.i = some_object[i].method(param=value)
そして、Pythonにボンネットの下でほとんどの解析をしてもらいます。アイデアはシンプルに基づいています exec <code> in <environment>
Ianが言及した声明、1つのハッキッシュな追加。つまり、関数のバイトコードをわずかに微調整し、すべてのローカル変数アクセス操作(load_fast)を環境から変数アクセス(load_name)に切り替える必要があります。
説明するよりも簡単に表示されます: http://fouryears.eu/wp-content/uploads/pydsl/
それを実用的にするためにあなたがやりたいと思うかもしれないさまざまなトリックがあります。たとえば、上記のリンクに表示されているコードでは、Loopsや@my_dsl関数内のステートメントなどのBuiltin関数や言語構造を使用することはできません。ただし、ENVクラスにさらに動作を追加することで、これらの作業を行うことができます。
アップデート. ここ 同じことの少し冗長な説明です。