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
This swapping should be implemented in your sorted data structures, not in this class for its instances.
For your own sanity, and that of whoever may use your code after you, if you decide to use this function, you should document the hell out of it so that you know what's going on. Your more self-documenting alternative, of course, is to write a function that swaps all the data members individually. Obviously this isn't very future-proof if your data model will be changing, but it will be less confusing. If it's not something you want to write out by hand, you could define a function to swap one data field, and run it over all your class attributes:
def swap (a, b):
for key in a.__dict__.keys():
swapOneField(key, a, b)
and for swapOneField
get the values from a.__dict__
and b.__dict__
and use the swapping algorithm of your choice. It's more verbose, and probably less efficient, but if you save more time in not debugging it than you lose in running it, it's probably worth your time.
If I understand correctly, you are actually swapping instances of a class, not classes.
Instance state is kept in two possible places: __slots__
and __dict__
. If you swap those, you've basically swapped instances while retaining the original name bindings. One caveat is that the class cannot be immutable (must not define __hash__()
) as any instances that were already members of a set or keys in a dictionary would then become irretrievable.
If it were me, I think I would have the .swap() method be a class method instead -- I think it would read easier:
class SomeBigClass():
@staticmethod
def swap_dict(instance_a, instance_b):
instance_a.__dict__, instance_b.__dict__ = \
instance_b.__dict__, instance_a.__dict__
@classmethod
def swap_slot(cls, instance_a, instance_b):
values = []
for attr in cls.__slots__:
values.append(
(attr,
getattr(instance_a, attr),
getattr(instance_b, attr),
))
for attr, val1, val2 in values:
setattr(instance_a, attr, val2)
setattr(instance_b, attr, val1)
and then later
SomeBigClass.swap_dict(this_instance, other_instance)
or
SomeBigClass.swap_slot(this_instance, other_instance)
Why shouldn't you do this? If you have instances bound to names you should not do this. Consider:
frubbah = SomeBigClass(attr="Hi, Mom!")
zikroid = SomeBigClass(attr='Hi, Dad!")
SomeBigClass.swap_dict(frubbah, zikroid)
After the swap, potentially everything you thought you knew about zikroid has changed.
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".
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'