Автоматически переадресовывать все переменные, относящиеся к объекту

Предположим, что у меня в 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 () без использования промежуточного прокси-объекта? Это явно невозможно с помощью метода, который я представил, но, возможно, есть какая-то магия, о которой я не знаю.

Как указывает Аарон, могут быть очень хрупкие и хрупкие решения, но, вероятно, ничего не будет гарантировано для работы во всех реализациях Python (например, CPython, IronPython, Jython, PyPy и т. Д.). Но почему бы реально попытаться сделать что-то, что противоречит дизайну и идиоматическому использованию языка, когда есть простые идиоматические решения? Вызов объекта класса обычно возвращает объект экземпляра. Имена привязаны к этому объекту. Вместо того, чтобы пытаться бороться с языком, придумывая хаки для отслеживания ссылок на объекты, чтобы обновлять привязки, естественным было бы создание объекта изменяемого экземпляра, при необходимости используя простую оболочку вокруг существующего класса.

Обновлено для 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)) 

Также вам не нужно переписывать ссылку, чтобы сделать экземпляр равным некоторому другому объекту. Вы можете просто написать

 new.__dict__ = old.__dict__ new.__class__ = old.__class__ 

Но это будет работать только с не встроенными экземплярами класса.

Обновить:

Я понял, как заставить его работать с кортежами. Это в основном решение 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 

неверный ответ

удаленный

Может быть, и, может быть, вы ищете Синглтон

 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()