假设我在python中有这个对象
class Foo:
def __init__(self, val):
self.val = val
和这两个变量
a=Foo(5)
b=a
b
和a
都引用Foo()
的同一个实例,因此对.val
属性的任何修改都会被视为同等且同步为a.val
和b.val
。
>>> b.val
5
>>> b.val=3
>>> a.val
3
现在假设我想说a=Foo(7)
。这将创建另一个Foo实例,因此现在a
和b
是独立的。
我的问题是:有没有办法让b
自动重新读取到新的Foo()实例,而不使用中间代理对象?用我提出的方法显然不可能,但也许有一些我不知道的魔法。
答案 0 :(得分:7)
正如Aaron指出的那样,可能存在非常简陋且易碎的解决方案,但可能无法保证所有Python实现(例如CPython,IronPython,Jython,PyPy等)都能正常工作。但是,当有简单的惯用解决方案时,为什么人们会想要做一些与语言的设计和习惯用法相悖的事情?调用类对象通常会返回一个实例对象。名称绑定到该对象。通过提出黑客来追踪对象的引用以更新绑定,而不是试图通过黑客来对抗语言,自然要做的是设计一个可变的实例对象,必要时使用现有类的简单包装器。
答案 1 :(得分:2)
更新了aaronasterling:
for d in gc.get_referrers(old):
if isinstance(d,list):
new_list = [ new if item is old else item for item in d]
while d: del d[-1]
d.extend(new_list)
elif isinstance(d,dict):
try:
for item in d:
if d[item] is old: d[item] = new
except Exception:pass
else: print('cant handle referrer at %i' % id(d))
此外,您不需要readdress引用使其实例等于某个其他对象。 你可以写
new.__dict__ = old.__dict__
new.__class__ = old.__class__
但这只适用于非内置类实例。
答案 2 :(得分:1)
我想出了如何让它与元组一起工作。这基本上是Odomontois的解决方案,删除了一些类型检查,并为元组递归。
import gc
import inspect
def update(obj, value):
objects = gc.get_referrers(obj)
old = obj # this protects our reference to the initial object
for o in objects:
if hasattr(o, '__iter__') and hasattr(o, 'extend'): # list like objects
new_list = [value if item is old else item for item in o]
while o: del o[-1]
o.extend(new_list)
elif hasattr(o, '__iter__') and hasattr(o, 'keys'): # dictionary like objects
for item in o.keys():
if o[item] is old: o[item] = value
elif isinstance(o, set):
o.remove(old)
o.add(value)
elif isinstance(o, tuple):
new_tuple = tuple(value if item is old else item for item in o)
update(o, new_tuple)
elif inspect.isframe(o):
continue
else:
raise Exception("can't handle referrer {0}".format(o))
class Test(object):
def __init__(self, obj):
self.val = obj
a = (1, ) #works
b = a #works
t = Test(b) #works because we this t.__dict__
L = [a] # works
S = set((a, )) # works
T = (a, ) # works
update(a, (2, ))
print a, b, t.val, L, S, T
删除
答案 3 :(得分:0)
也许,也许你正在寻找Singleton
class Singleton(type):
def __init__(cls, name, bases, dict):
super(Singleton, cls).__init__(name, bases, dict)
cls.instance = None
def __call__(cls, *args, **kw):
if cls.instance is None:
cls.instance = super(Singleton, cls).__call__(*args, **kw)
return cls.instance
class MyClass(object):
__metaclass__ = Singleton
print MyClass()
print MyClass()