[英]Pickling a “interned” object
假設我有一個叫做Symbol的類。 在任何給定時間,我只需要一個給定id的Symbol的一個副本。 例如
registry = {}
class Symbol(object):
def __init__(self, id):
self.id = id
def __eq__(self, other):
return self is other
def symbol(id):
if id not in registry:
registry[id] = Symbol(id)
return registry[id]
我希望能夠腌制我的Symbol對象,但是我不知道如何讓cPickle調用我的Symbol工廠。 現在,我可以實現getstate / setstate重寫,但是仍然不能將未選擇的對象與注冊表中已經存在的對象合並。 如何在保留符號與ID的1:1比例的同時使上述類腌制?
編輯(標題更新為“ interned”而不是“ singleton”):
讓我解釋一下用例。 我們將這些符號用作字典中的鍵。 徹底拘留他們可以提高績效
我需要發生的事情:
x = symbol("x")
y = pickle.loads(pickle.dumps(x))
x is y == True
由於您不希望多個對象具有給定的ID,因此請提供自定義__new__
方法來代替symbol
函數。
class Symbol(object):
registry = {}
def __new__(cls, *args, **kwargs):
id_ = args[0]
return Symbol.registry.setdefault(_id, object.__new__(cls, *args, **kwargs))
def __init__(self, id):
self.id = id
現在,您不需要工廠函數即可創建Symbol
對象。
$ a = Symbol('=')
$ b = Symbol('=')
$ a is b
True
您可能想將weakref的WeakValueDictionary用於符號注冊表,以便在不再引用Symbol時,垃圾回收可以回收內存。
您可以使用以下類來定義什么是實習對象。 然后,您的Symbol類(或任何其他類)可以從中繼承。
class Interned (object):
# you need to create this registry in each class if the keys are not unique system-wide
registry = weakref.WeakValueDictionary()
def __new__(cls, *args, **kwargs):
assert 0 < len(args)
if not args[0] in cls.registry: # don't use setdefault to avoid creating unnecessary objects
o = object.__new__(cls, *args, **kwargs) # o is a ref needed to avoid garbage collection within this call
cls.registry[args[0]] = o
return o
return cls.registry[args[0]]
def __eq__(self, other):
return self is other
def __hash__(self):
# needed by python 3
return id(self)
def __ne__(self, other):
return not self is other
您的代碼變為:
class Symbol(Interned):
def __init__(self, id):
self.id = id
導致:
$ a = Symbol('=')
$ b = Symbol('=')
$ a is b
True
您可以嘗試使用pickle.Unpickler
子類,並在load
方法中實現您的加載邏輯。
但是您將需要某種鍵來知道對象在運行時是否已經存在(返回引用而不是新實例)。 這將導致您重新實現python對象空間。
我建議嘗試尋找另一個更適合您實際問題的數據結構。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.