2012-03-28 2 views
0

Symbol 클래스가 있습니다. 어떤 주어진 시간에, 나는 주어진 id를 가진 하나의 Symbol 사본 하나를 원한다. "interned"객체 pickling

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] 
예를

를 들어 내 기호 객체를 피클 수 있도록하고 싶습니다,하지만 난의 cPickle 내 기호 공장 전화를 얻는 방법을 알아낼 수 없습니다. 이제 getstate/setstate 재정의를 구현할 수는 있지만 패킹되지 않은 객체를 레지스트리에 이미 존재하는 객체와 병합하지는 않습니다. 심벌과 ID의 1 : 1 비율을 유지하면서 위의 클래스를 피클 링하는 방법은 무엇입니까?


편집 (상태 업데이트 제목 대신 "싱글"의 "구금") :

날 사용 사례를 설명하겠습니다. 우리는 이러한 기호를 사전에 키로 사용하고 있습니다.

x = symbol("x") 

y = pickle.loads(pickle.dumps(x)) 

x is y == True 
+2

그냥 싱글을 사용하지 마십시오

class Symbol(Interned): def __init__(self, id): self.id = id 

는 결과? – delnan

+0

글쎄, 내 실제 경우에는 기호가 여분의 메타 데이터의 여러 필드를 가질 수 있습니다 "x는 y를 기반으로 비교"는 "x.foo == y.foo 및 x.bar == y보다 빠른 방법이 될 것입니다. bar와 ... " –

+1

피클은'__init__'을 호출하지 않지만'__new__'를 호출합니다. – georg

답변

3

주어진 ID로 둘 이상의 개체가 필요하지 않으므로 symbol 함수 대신 맞춤 __new__ 메서드를 제공하십시오.

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 
0

당신은 그래서 서브 클래스 pickle.Unpickler을 시도하고 load 방법에 로딩 로직을 구현할 수 있습니다 그들을 크게 구금 할 수있는 것은 성능

내가 가질 필요가 무엇

일이 향상됩니다.

그러나 런타임에 객체가 이미 존재하는지 (새 인스턴스가 아닌 참조를 반환하기 위해) 알 수있는 종류의 키가 필요합니다. 이것은 파이썬 객체 공간의 재 구현으로 인도 할 것이다.

실제 문제에보다 적합한 다른 데이터 구조를 찾으려고합니다.

0

당신은 기호가 더 이상 참조되지 않은 때 가비지 콜렉션이 메모리를 회수 할 수 있도록, 기호 레지스트리에 대한 weakrefWeakValueDictionary를 사용할 수 있습니다.

다음 클래스를 사용하여 인턴 된 개체를 정의 할 수 있습니다. 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 

코드는된다 :

$ a = Symbol('=') 
$ b = Symbol('=') 
$ a is b 
True 
관련 문제