로 시작하려면 :
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError:
...
하지만 그건 당신이 밖에서 글로벌 변수를 검색 할 수 없습니다 나는 NameError
의 정상 이름 확인을 계속 잡을 어떻게 클래스 바디. 같은 SymPy와 SQLAlchemy의 파이썬 물건 고급이에 의지 한 - "UnPythonic"는 것을
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
당신이 볼 수 있듯이, 그되지 않습니다 : 또한 딕셔너리의 서브 클래스 정확히 예약 된 __missin__
방법을 사용할 수 있습니다 친절한 행동을 통해 좋은 마술을 행할 수 있습니다. 문서화되고 테스트를 거쳐야합니다.
이제 전역 (모듈) 변수를 허용하기 위해 모든 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
은 어떻게됩니까 th이다 c
에있는 개체는 ForwardDeclaration
개체가되지만 즉시 값 d
인 0이됩니다. 다음 줄에서 d
은 단순히 값 1
으로 덮어 쓰여지고 더 이상 게으른 개체가 아닙니다. 따라서 c = 0 + b
을 선언 할 수도 있습니다.
이것을 극복하려면 스마트 웨이에서 설계된 클래스 여야하며 그 값은 항상 느슨하게 평가되고 "반응 형 프로그래밍"접근 방식과 같이 동작해야합니다. 즉, 값을 업데이트하면 업데이트가 계단식으로 연결됩니다. 그것에 의존하는 다른 모든 값. 나는 당신에게 "반응하는"인식 FOrwardDeclaration 클래스의 완전한 구현을 제공하는 것이이 질문의 범위에서 벗어난 것이라고 생각한다. - 나는 장난감 코드를 가지고 있기 때문에, github에서 할 수 있습니다.
에도 적절한 "반응성"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
하나 개의 클래스의 DICT _forward_dependencies
을 업데이트 rememebr. +
이외의 연산자가 필요하다면,주의해야 할 것은 연산자 자체에 대한 정보를 보관해야합니다.이 시점에서 sympy
을 사용할 수도 있습니다.
기본 인수 (이 경우 특성)를 사용하여이 문제를 해결할 수 없습니까? – Rockybilly
내가 당신을 오해하지 않는다면, MyClass의 속성이 무엇인지'MyBaseClass'를 정의 할 때 알 수 없으므로 작동하지 않을 것입니다. 내가 그랬다면, 당신은 옳을 것이다. 나는 그것들을 모두 기본 클래스에'd = ForwardDeclaration()'과 같이 선언 할 수 있습니다. – drhagen
이것은 역 겹게 역겨운 것처럼 들린다! 잘 했어! 특정 문제/질문이 무엇인지는 분명하지 않습니다. –