簡體   English   中英

腌制“被拘留”的物體

[英]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

您可能想將weakrefWeakValueDictionary用於符號注冊表,以便在不再引用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM