2014-04-12 6 views
5

파이썬 디스크립터를 사용할 때 일반적인 디자인 패턴은 디스크립터에 해당 디스크립터를 사용하는 인스턴스 사전을 보관하게하는 것이다. 예를 들어, 내가 액세스 것 횟수 카운트 속성 만들고 싶어한다고 가정 유용 아무것도하지 않는 완전히 바보 예입니다unhashable 클래스에서 디스크립터 사용 - 파이썬

class CountingAttribute(object): 

    def __init__(self): 
     self.count = 0 
     self.value = None 


class MyDescriptor(object): 

    def __init__(self): 
     self.instances = {} #instance -> CountingAttribute 

    def __get__(self, inst, cls): 
     if inst in self.instances: 
      ca = self.instances[inst] 
     else: 
      ca = CountingAttribute() 
      self.instances[inst] = ca 
     ca.count += 1 
     return ca 


class Foo(object): 
    x = MyDescriptor() 


def main(): 
    f = Foo() 
    f.x 
    f.x 
    print("f.x has been accessed %d times (including the one in this print)"%(f.x.count,)) 

if __name__ == "__main__": 
    main() 

을; 나는 요점을 격리하려고 노력하고있다.

문제는 라인

self.instances[inst] = ca 

가 사전 키로 인스턴스를 사용하기 때문에 내가, 해쉬없는 클래스 기술자를 사용할 수 있다는 것입니다. 이런 종류의 사건을 처리하는 현명한 방법이 있습니까? 예를 들어, 즉시 인스턴스의 id을 사용한다고 생각하지만, 그렇게하면 해시가 사용되는 방식에 대한 문제가 발생하는지 확실하지 않습니다.

편집 : instancesweakref.WeakKeyDictionary과 같아야한다는 것을 알고 있지만 간단하게 해시 가능성 문제에 집중하려고 노력 중입니다.

+1

첫 번째 생각은''인스턴스 '에 대해 ['WeakKeyDictionary'] (https://docs.python.org/3.4/library/weakref.html#weakref.WeakKeyDictionary)를 사용해 보았습니다. 불행히도, 이것은 unhashability의 근본적인 문제를 해결하는 것 같지 않지만 그럼에도 불구하고 좋은 생각입니다. (그렇지 않으면 디스크립터는 그렇지 않으면 죽은 객체를 계속 유지할 것입니다.) – icktoofay

+0

예, 실제 구현에서는 WeakKeyDictionary를 사용합니다. 나는 여기서 그 질문에 초점을 맞추려고 노력하고 있기 때문에 여기서하지 않았다. – DanielSank

답변

3

id(inst)을 키로 사용할 수 있습니다.

개체가 파괴되어 새로운 ID로 새 개체가 만들어지는 경우에는 해당되지 않습니다.

올바르게 감지하려면 사전에 weakref 인 ca을 저장해야합니다. weakref의 참조 된 객체가 사라진 것을 감지하면 주어진 id가 다시 사용되었다고 가정해야합니다.

import weakref 

class MyDescriptor(object): 

    def __init__(self): 
     self.instances = {} #instance -> CountingAttribute 

    def __get__(self, inst, cls): 
     if inst is None: return self.instances # operating on the class, we get the dictionary. 
     i = id(inst) 
     if i in self.instances: 
      ca, wr = self.instances[i] 
      if wr() is None: del self.instances[i] 
     if i not in self.instances: 
      ca = CountingAttribute() 
      self.instances[i] = (ca, weakref.ref(inst)) 
     ca.count += 1 
     return ca 

이것은 WeakKeyDictionary에 conntected hashability의 문제를 해소 같은

뭔가.

하지만 어쩌면 당신은 전혀 필요하지 않을 수 있습니다. 전혀 다른 접근 방식이 될 수 있습니다.

class MyDescriptor(object): 

    def __get__(self, inst, cls): 
     if inst is None: return self, cls 
     try: 
      ca = inst.__the_ca 
     except AttributeError: 
      ca = inst.__the_ca = CountingAttribute() 
     ca.count += 1 
     return ca 

이 접근법은 단점도 가지고 있습니다. 예를 들어, 클래스에서 설명자를 두 번 이상 쉽게 사용할 수는 있습니다. 따라서,주의해서 사용해야합니다. 첫 번째 해결책은 복잡하지만 복잡하지 않은 방법입니다.

+0

약한 참조 란 무엇입니까? :) – DanielSank

+0

@ 대니얼 삭스 편집 됨. – glglgl

+0

이것은 정말 영리합니다. – DanielSank

관련 문제