是否有可能超载Python分配?

是否有一个神奇的方法,可以重载赋值运算符,如__assign__(self, new_value)

我想禁止重新绑定一个实例:

 class Protect(): def __assign__(self, value): raise Exception("This is an ex-parrot") var = Protect() # once assigned... var = 1 # this should raise Exception() 

可能吗? 疯了吗? 我应该吃药吗?

你描述的方式是绝对不可能的。 赋值给一个名字是Python的一个基本特征,并没有提供任何钩子来改变它的行为。

但是,通过覆盖.__setattr__()可以根据需要控制对类实例中成员的赋值。

 class MyClass(object): def __init__(self, x): self.x = x self._locked = True def __setattr__(self, name, value): if self.__dict__.get("_locked") and name == "x": raise AttributeError, "MyClass does not allow assignment to .x member" self.__dict__[name] = value >>> m = MyClass(3) >>> mx 3 >>> mx = 4 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 7, in __setattr__ AttributeError: MyClass does not allow assignment to .x member 

请注意,有一个成员variables_locked ,用于控制赋值是否被允许。 你可以解锁它来更新值。

不,因为作业是一种没有修改钩子的语言内在 。

我不认为这是可能的。 我看到它的方式,赋值给一个variables不会对之前提到的对象做任何事情:只是variables“指向”一个不同的对象。

 In [3]: class My(): ...: def __init__(self, id): ...: self.id=id ...: In [4]: a = My(1) In [5]: b = a In [6]: a = 1 In [7]: b Out[7]: <__main__.My instance at 0xb689d14c> In [8]: b.id Out[8]: 1 # the object is unchanged! 

但是,您可以通过使用__setitem__()__setattr__()方法创build包装对象来模仿所需的行为,从而引发exception,并将“不可更改”的内容保留在内部。

没有没有

考虑一下,在你的例子中,你正在重新命名var为一个新的值。 你实际上并没有触及Protect的实例。

如果您希望重新绑定的名称实际上是某个其他实体的属性,即myobj.var,那么您可以防止为该实体的属性/属性分配一个值。 但是我认为这不是你想要的。

在全局命名空间中,这是不可能的,但是您可以利用更高级的Python元编程来防止创buildProtect对象的多个实例。 Singleton模式就是一个很好的例子。

在Singleton的情况下,您可以确保一旦实例化,即使引用实例的原始variables被重新分配,该对象也会保留。 任何后续的实例只会返回对同一个对象的引用。

尽pipe这种模式,你永远不能防止全球variables名称被重新分配。

使用顶级命名空间,这是不可能的。 当你跑步

 `var = 1` 

它将关键字var和值1在全局字典中。 这大致相当于调用globals().__setitem__('var', 1) 。 问题是你不能在一个正在运行的脚本中replace全局字典(你可能可以通过乱搞堆栈,但这不是一个好主意)。 但是,您可以在辅助命名空间中执行代码,并为其全局提供自定义字典。

 class myglobals(dict): def __setitem__(self, key, value): if key=='val': raise TypeError() dict.__setitem__(self, key, value) myg = myglobals() dict.__setitem__(myg, 'val', 'protected') import code code.InteractiveConsole(locals=myg).interact() 

这将触发一个几乎正常运行的REPL,但拒绝尝试设置variablesval 。 你也可以使用execfile(filename, myg) 。 请注意,这不能防止恶意代码。

一个丑陋的解决scheme是重新分配的析构函数。 但这不是真正的超载分配。

 import copy global a class MyClass(): def __init__(self): a = 1000 # ... def __del__(self): a = copy.copy(self) a = MyClass() a = 1 

是的,这是可能的,你可以通过修改ast处理__assign__

pip install assign

testing:

 class T(): def __assign__(self, v): print('called with %s' % v) b = T() c = b 

你会得到

 >>> import magic >>> import test called with c 

该项目是在https://github.com/RyanKung/assign更简单的要点: https://gist.github.com/RyanKung/4830d6c8474e6bcefa4edd13f122b4dfhttps://gist.github.com/RyanKung/4830d6c8474e6bcefa4edd13f122b4df