我可以通过交换__dict__来有效地交换两个类实例吗?
问题内容:
我有一个很大的类,成员很多,周围有很多关于此类实例的参考。不幸的是(出于合理的原因)所有这些参考都是错误的方法。
我定义了一个方法,而不是重新创建每个对象(并在引用对象的任何地方查找和更新),或者每次我访问此类或单独交换成员时都添加额外的间接级别,而不是:
def swap(self, other):
assert(isinstance(other, self.__class__))
self.__dict__, other.__dict__ = other.__dict__, self.__dict__
所以我可以做:
instance_a.swap(instance_b)
# now all references to instance_a everywhere are as if instance_a is instance_b
问题: 似乎工作正常(我不使用__slots__
),但感觉可能是我不应该这样做的原因,在吗?
这是我的实际用例:
我有一种类型,它以(必需)昂贵的方式实现比较运算符。我有各种排序的数据结构,其中包含这种类型的对象。
当我对其中一个对象执行操作时,我知道比较顺序已更改,并且可以通过将修改后的对象与“下一个更大的”对象交换来恢复数据结构中的顺序(所有这些!)。
问题答案:
如果我理解正确,那么您实际上是在交换一个类的实例,而不是类。
实例状态保存在两个可能的位置: __slots__
和中__dict__
。如果交换它们,则基本上交换了实例,同时保留了原始名称绑定。一个警告是,该类
不能 是不变的(必须不定义__hash__()
),因为任何已经是集合成员或字典中键的实例都将变得不可检索。
如果是我,我想我应该将.swap()方法改为一个类方法-我认为它将更容易阅读:
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)
然后再
SomeBigClass.swap_dict(this_instance, other_instance)
要么
SomeBigClass.swap_slot(this_instance, other_instance)
你为什么不这样做呢?如果您有实例绑定到名称,则不应这样做。考虑:
frubbah = SomeBigClass(attr="Hi, Mom!")
zikroid = SomeBigClass(attr='Hi, Dad!")
SomeBigClass.swap_dict(frubbah, zikroid)
交换之后,您认为自己对zikroid所了解的一切可能都已改变。