Python copy-on-write行为

DMa*_*ack 7 python flyweight-pattern python-2.7

我正在研究一个问题,我正在实例化一个对象的许多实例.大多数情况下,实例化的对象是相同的.为了减少内存开销,我想让所有相同的对象指向同一个地址.但是,当我修改对象时,我想要创建一个新实例 - 基本上是写时复制行为.在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
Run Code Online (Sandbox Code Playgroud)

其行为如下:

>>> c1 = Card('10', 'd')
>>> c2 = Card('10', 'd')
>>> id(c1) == id(c2)
True
>>> c2.suit = 's'
>>> c1.suit
's'
>>> id(c1) == id(c2)
True
Run Code Online (Sandbox Code Playgroud)

期望的行为是:

>>> c1 = Card('10', 'd')
>>> c2 = Card('10', 'd')
>>> id(c1) == id(c2)
True
>>> c2.suit = 's'
>>> c1.suit
'd'
>>> id(c1) == id(c2)
False
Run Code Online (Sandbox Code Playgroud)

更新:我遇到了Flyweight模式,它似乎几乎适合该法案.但是,我对其他方法持开放态度.

Bre*_*own 6

你需要id(c1)==id(c2)相同,还是只是一个演示,真正的目标是避免创建重复的对象?

一种方法是让每个对象都是不同的,但是像上面一样保持对"真实"对象的内部引用.然后,在任何__setattr__呼叫中,更改内部参考.

我以前从未做过__setattr__东西,但我认为它看起来像这样:

class MyObj:
    def __init__(self, value, suit):
        self._internal = Card(value, suit)

    def __setattr__(self, name, new_value):
        if name == 'suit':
            self._internal = Card(value, new_value)
        else:
            self._internal = Card(new_value, suit)
Run Code Online (Sandbox Code Playgroud)

同样,通过公开属性getattr.

你仍然有很多重复的对象,但只有一个"真正的"支持对象的副本.因此,如果每个对象都很庞大,这将有所帮助,如果它们是轻量级的,那将无济于事,但是你有数百万个.