我想建立一个代码模式,允许我执行类似于以下内容的操作:
# Foo has getter-only properties
foo: Foo = FooRepo.get(id="foo_id")
assert foo.bar == "original_bar"
# MutableFoo is a window onto the Foo, and when it __exit__s, it persists to the repo
with foo.mutable() as mutable_foo:
mutable_foo.bar = "new_bar"
# We've updated the Foo, as well as whatever persistent version the FooRepo owns
assert foo.bar == "new_bar"
我并不执着于确切的代码模式。我喜欢它的地方:
Foo
传递到许多代码区域,只要 mutable()
没有被调用,我们就可以将其视为不可变并忽略持久性的想法。ContextManager
。在 ContextManager
之外,我们可以将对象视为快照,这会更常见并且不那么毛茸茸的。我看到的挑战:
with
块之外创建可变版本。Foo
的任何接口都可以使 MutableFoo
进行突变。 (你能看出我已经习惯了 Java 吗?缺少可以访问私有成员的内部类让我有点摸不着头脑)有人用 Python 构建过此类框架吗?您喜欢什么解决方案?
您可以创建一个“不可变”代理对象,通过引发异常来禁用 setter 和 deleter 方法。禁止通过实现上下文管理器来设置新属性,该上下文管理器在进入时返回原始可变对象以允许上下文内发生突变:
def protected(obj):
class Protected(type(obj)):
def __getattr__(self, name):
return getattr(obj, name)
def __setattr__(self, name, value):
raise AttributeError("can't set attribute")
def __delattr__(self, name):
raise AttributeError("can't delete attribute")
def __enter__(self):
return obj
def __exit__(self, exc_type, exc_val, exc_tb):
pass
return object.__new__(Protected)
这样下面的代码就可以通过断言:
class Foo:
def __init__(self, bar):
self.bar = bar
foo = protected(Foo('original_bar'))
with foo as mutable_foo:
mutable_foo.bar = 'new_bar'
assert foo.bar == 'new_bar'
而以下代码会引发
AttributeError
:
foo.bar = 'new_bar'