我正在处理一个问题,我正在实例化一个对象的多个实例。大多数情况下,实例化的对象是相同的。为了减少内存开销,我希望所有相同的对象都指向同一个地址。但是,当我修改对象时,我希望创建一个新实例——本质上是写时复制行为。在Python中实现这一点的最佳方法是什么?在
Flyweight图案更接近。示例(来自http://codesnipers.com/?q=python-flyweights):
import weakref
class Card(object):
_CardPool = weakref.WeakValueDictionary()
def __new__(cls, value, suit):
obj = Card._CardPool.get(value + suit, None)
if not obj:
obj = object.__new__(cls)
Card._CardPool[value + suit] = obj
obj.value, obj.suit = value, suit
return obj
其行为如下:
^{pr2}$期望的行为是:
>>> c1 = Card('10', 'd')
>>> c2 = Card('10', 'd')
>>> id(c1) == id(c2)
True
>>> c2.suit = 's'
>>> c1.suit
'd'
>>> id(c1) == id(c2)
False
更新:我偶然发现了Flyweight模式,它似乎几乎符合要求。不过,我对其他方法持开放态度。在
您是否需要
id(c1)==id(c2)
完全相同,或者这只是一个演示,真正的目标是避免创建重复的对象?在一种方法是让每个对象都是不同的,但像上面所说的那样保存对“真实”对象的内部引用。然后,在任何
__setattr__
调用中,更改内部引用。在我以前从未做过
__setattr__
的事情,但我想应该是这样的:类似地,通过
getattr
公开属性。在你仍然有很多重复的对象,但是只有一个“真实”的备份对象在它们后面。所以如果每个物体都是大的,这会有帮助,如果它们很轻的话也不会有帮助,但是你有数百万个这样的物体。在
不可能。在
表示}是对同一对象的引用。所以
c1
和{c2.suit = 's'
与c1.suit = 's'
完全相同。在Python无法区分这两者(除非允许对以前的调用帧进行内省,这会导致一次肮脏的黑客攻击)
由于这两个赋值是相同的,Python无法知道
c2.suit = 's'
应该导致名称c2
引用不同的对象。在为了让你知道这个肮脏的黑客会是什么样子
^{pr2}$这种回溯的使用只适用于那些使用框架的Python实现,例如CPython,而不是Jython或IronPython。在
另一个问题是
是非常脆弱的,而且如果任务看起来像
或者
或者
另一个问题是它假设名称
c2
是全局的。它可以很容易地成为一个局部变量(比如,在一个函数中),或者一个属性(obj.c2.suit = 's'
)。在我不知道一个方法来解决所有可能的任务。在
在任何一种情况下,肮脏的黑客攻击都会失败。在
结论:不要用它。:)
以你目前的状态这是不可能的。名称(}在您的示例中)是一个引用,您不能简单地通过使用
c1
和{__setattr__
来更改引用,更不用说对同一对象的所有其他引用。在唯一可能的办法是:
其中
c1.changesuit
返回对(新创建的)对象的引用。但只有当每个对象只被一个名称引用时,这才有效。或者你可以用locals()
之类的东西来做一些魔术,但是请不要相关问题 更多 >
编程相关推荐