我有一个有很多成员的大班,并且有很多关于这个类的实例的引用.不幸的是(出于合理的原因)所有这些引用都是错误的方法.
而不是重新创建每个(并在任何地方查找和更新对象),或者每次访问此类时添加额外的间接级别,或者单独交换成员,我都定义了一个方法:
def swap(self, other):
assert(isinstance(other, self.__class__))
self.__dict__, other.__dict__ = other.__dict__, self.__dict__
Run Code Online (Sandbox Code Playgroud)
所以我可以这样做:
instance_a.swap(instance_b)
# now all references to instance_a everywhere are as if instance_a is instance_b
Run Code Online (Sandbox Code Playgroud)
问题:
它似乎工作正常(我不使用__slots__
),但感觉可能有一个原因我不应该这样做,是吗?
这是我的实际用例:
我有一种以(必然)昂贵的方式实现比较运算符的类型.我有各种包含此类对象的排序数据结构.
当我对其中一个对象执行某些操作时,我知道比较顺序已更改,并且可以通过将修改后的对象与"下一个更大"的对象进行交换来恢复数据结构中的顺序(所有这些!).
你正在做的事情是可能的,虽然它会让人感到畏缩,因为它是黑客.如果可能的话,我建议您考虑重写/重构您的比较运算符.到目前为止,这将给你最好的结果.当然,不知道所涉及的范围或时间范围,很难说这是否立即可行,但相信我,如果你能做"正确"的事情,你将花更少的时间重写长期.
实际上,听起来你正在处理三个类 - 一个数据对象和两个实用程序类 - 但这是另一个问题.
这会打破,所以我要继续说"不,你不能通过交换__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'
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,你实际上是在交换类的实例,而不是类.
实例状态保存在两个可能的位置: __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)
Run Code Online (Sandbox Code Playgroud)
然后是
SomeBigClass.swap_dict(this_instance, other_instance)
Run Code Online (Sandbox Code Playgroud)
要么
SomeBigClass.swap_slot(this_instance, other_instance)
Run Code Online (Sandbox Code Playgroud)
你为什么不这样做?如果您有绑定名称的实例,则不应执行此操作.考虑:
frubbah = SomeBigClass(attr="Hi, Mom!")
zikroid = SomeBigClass(attr='Hi, Dad!")
SomeBigClass.swap_dict(frubbah, zikroid)
Run Code Online (Sandbox Code Playgroud)
在交换之后,你认为你知道zikroid的一切可能都发生了变化.
归档时间: |
|
查看次数: |
1634 次 |
最近记录: |