Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I efficiently swap two class instances by swapping __dict__?

Tags:

python

I have a big class with lots of members, and quite a few references to instances of this class lying around. Unfortunately (for reasonable reasons) all these references are the wrong way around.

Instead of re-creating each (and finding and updating everywhere the objects are referenced), or adding an extra level of indirection each time I access this class, or individually swapping members, I have defined a method:

def swap(self, other):
    assert(isinstance(other, self.__class__))
    self.__dict__, other.__dict__ = other.__dict__, self.__dict__

so I can do:

instance_a.swap(instance_b)
# now all references to instance_a everywhere are as if instance_a is instance_b

The question: It seems to work fine (I don't use __slots__), but it feels like there might be a reason I shouldn't do this, is there?


Here's my actual use case:

I have a type that implements comparison operators in a (necessarily) expensive way. I have various sorted data-structures containing objects of this type.

When I do something to one of the objects, I know that the comparison order has changed, and that order in my data structures (all of them!) can be restored by swapping the modified object with the 'next bigger' one.

like image 974
James Avatar asked Aug 31 '11 10:08

James


People also ask

How does Python swapping work?

Python stores results on a stack. For swapping variables, it can load them on the stack, swap the order of the top two variables, and then store them back, now in opposite order.


1 Answers

Edit

What you're doing is possible, although it will make people cringe because it is hackish. If at all possible, I would suggest that you look at rewriting/refactoring your comparison operators. That will give you the best outcome by far. Of course, not knowing the scope or time-frame involved, it is very difficult to tell whether this is immediately practical, but trust me, you will spend less time re-writing in the long term if you can do things "right".

Original

Realistically, it sounds like you're dealing with three classes -- a data object and two utility classes -- but that is another issue.

This will break, so I am going to go ahead and say, "no, you cannot swap classes by swapping __dict__s":

>>> class Foo:
...    def __init__(self):
...        self.__bar = 1
...    def printBar(self):
...        print self.__bar
... 
>>> class Bar:
...    def __init__(self):
...        self.__bar=2
...    def printBar(self):
...        print self.__bar
... 
>>> f=Foo()
>>> f.printBar() # works as expected
1
>>> f=Foo()
>>> b=Bar()
>>> f.__dict__, b.__dict__ = b.__dict__, f.__dict__
>>> f.printBar() # attempts to access private value from another class
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in printBar
AttributeError: Foo instance has no attribute '_Foo__bar'
like image 93
cwallenpoole Avatar answered Nov 01 '22 13:11

cwallenpoole