开发者

Automatically readdress all variables referring to an object

Suppose I have in python this object

class Foo:  
    def __init__(self, val):
        self.val = val

and these two variables

a=Foo(5)
b=a

both b and a refer to the same instance of Foo(), so any modification to the attribute .val will be seen equally and synchronized as a.val and b.val.

>>> b.val
5
>>> b.val=3
>>> a.val
3

Now suppose I want to say a=Foo(7). This will create another instance of Foo, so now a and b are independent.

My question is: is there a way to have b readdressed automatically to the new Foo() instance, without using an intermediate proxy object? It's clearly not possible with the method I present开发者_运维问答ed, but maybe there's some magic I am not aware of.


As Aaron points out, there may be very hacky and fragile solutions but there is likely nothing that would be guaranteed to work across all Python implementations (e.g. CPython, IronPython, Jython, PyPy, etc). But why would one realistically want to do something that is so contrary to the design and idiomatic use of the language when there are simple idiomatic solutions available? Calling a class object typically returns an instance object. Names are bound to that object. Rather than trying to fight the language by coming up with hacks to track down references to objects in order to update bindings, the natural thing would be to design a mutable instance object, if necessary using a simple wrapper around an existing class.


Updated for 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))

Also you dont need to readdress reference to make it's instance equal to some other object. You can just write

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

But this will work only with not-built-in class instances.


update:

I figured out how to make it work with tuples. This is basically Odomontois' solution with some type checking removed and made recursive for tuples.

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

wrong answer

deleted


Maybe and just maybe you're looking for a 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()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜