を:
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError:
...
しかし、それはあなたが外でグローバル変数を取得することはできませんクラスボディ。 ます。また、辞書のサブクラスのために、正確に予約されて__missin__
方法を使用することができます:あなたが見ることができるように
class MetaDict(dict):
def __init__(self):
self._forward_declarations = dict()
# Just leave __getitem__ as it is on "dict"
def __missing__(self, key):
if key in self._forward_declarations:
return self._forward_declarations[key]
else:
new_forward_declaration = ForwardDeclaration()
self._forward_declarations[key] = new_forward_declaration
return new_forward_declaration
を、それが「UnPythonic」ということではありません - 高度なPythonのものなどSymPyとSQLAlchemyのようにはこれに頼る必要があり彼らの素敵な魔法をやるための行動の種類 - それは非常によく文書化され、テストを取得することを確認してください。
グローバル(モジュール)変数を使用できるようにするには、ちょっとした手間を省いてください。すべてのPython実装では使用できないかもしれません。つまり、クラス本体があるフレームをイントロスペクションするそのグローバル得るために:今、あなたはここにいることを
import sys
...
class MetaDict(dict):
def __init__(self):
self._forward_declarations = dict()
# Just leave __getitem__ as it is on "dict"
def __missing__(self, key):
class_body_globals = sys._getframe().f_back.f_globals
if key in class_body_globals:
return class_body_globals[key]
if key in self._forward_declarations:
return self._forward_declarations[key]
else:
new_forward_declaration = ForwardDeclaration()
self._forward_declarations[key] = new_forward_declaration
return new_forward_declaration
を - あなたの特別な辞書はNameErrorsを回避するのに十分なほど良いですが、あなたのForwardDeclaration
オブジェクトが十分にスマートからです - 実行しているとき:
a = 1
class MyClass(MyBaseClass):
b = a # Refers to something outside the class
c = d + b # Here's a forward declaration to 'd'
d = 1
どうなりますかあなたはc
のオブジェクトはForwardDeclaration
オブジェクトになりますが、瞬時値d
に合計されます。これはゼロです。次の行では、d
は単に値1
で上書きされ、もはや遅延オブジェクトではありません。だから、ちょうど同様にc = 0 + b
を宣言するかもしれません。
これを解決するには、ForwardDeclaration
はスマートウェイで設計されたクラスでなければならず、その値は常に怠惰に評価され、 "リアクティブプログラミング"アプローチのように振る舞います。それに依存する他のすべての値。私はあなたに働く "反応的"なFOrwardDeclarationクラスの完全な実装を与えることは、この質問の範囲から外れると思います。 - 私はgithubでhttps://github.com/jsbueno/python-reactにそれを行うためのおもちゃのコードを持っています。
でも適切な「反応性」ForwardDeclarationクラスで、あなたはd = 1
クラスが機能するように、もう一度あなたの辞書を修正する必要があります。
class MetaDict(dict):
def __init__(self):
self._forward_declarations = dict()
def __setitem__(self, key, value):
if key in self._forward_declarations:
self._forward_declations[key] = value
# Trigger your reactive update here if your approach is not
# automatic
return None
return super().__setitem__(key, value)
def __missing__(self, key):
# as above
そして最後に、完全に反応を実施するhavignを回避する方法があります意識クラス - あなたはメタクラスの__new__
法上の保留中のすべてのFOrwardDependenciesを解決することができます - (あなたのForwardDeclarationオブジェクトは、クラスの作成時に「凍結」、ノーさらに心配手動であるように - )に沿って
何か:
from functools import reduce
sentinel = object()
class ForwardDeclaration:
# Minimal behavior
def __init__(self, value=sentinel, dependencies=None):
self.dependencies = dependencies or []
self.value = value
def __add__(self, other):
if isinstance(other, ForwardDeclaration):
return ForwardDeclaration(dependencies=self.dependencies + [self])
return ForwardDeclaration(self.value + other)
class MyMeta(type):
def __new__(metacls, name, bases, attrs):
for key, value in list(attrs.items()):
if not isinstance(value, ForwardDeclaration): continue
if any(v.value is sentinel for v in value.dependencies): continue
attrs[key] = reduce(lambda a, b: a + b.value, value.dependencies, 0)
return super().__new__(metacls, name, bases, attrs)
def __prepare__(mcs, name, bases):
return MetaDict()
そして、あなたのクラス階層と正確に何をやっているに応じて、また、その祖先で作成し_forward_dependencies
で1クラスのdictの_forward_dependencies
を更新するrememebr。 +
以外の演算子が必要な場合は、注意したように、演算子自体に関する情報を保持する必要があります。この時点では、sympy
を使用することもできます。
デフォルトの引数(ここでは属性)を使用してこれを解決できませんでしたか? – Rockybilly
私があなたを誤解していない限り、私は 'MyClass'の属性を' MyBaseClass'と定義した時点ではわからないので、うまくいきません。もし私がしたら、あなたは正しいでしょう。基本クラスの 'd = ForwardDeclaration()'のようにすべて宣言できます。 – drhagen
これは陽気にうんざりするように聞こえる!よくやった!特定の問題/質問が何であるかはっきりしていませんか? –