2017-11-13 20 views
3

생성자를 메모 할 수있는 데코레이터를 작성하고 싶습니다. 클래스를 생성 할 때 가능하면 객체가 캐시에서 반환되기를 바랍니다.왜이 경우 isinstance()가 False를 반환합니까?

다음 코드는 here에서 수정되었습니다.

from functools import wraps 


def cachedClass(klass): 
    cache = {} 

    @wraps(klass, updated=()) 
    class wrapper: 
     def __new__(cls, *args, **kwargs): 
      key = (cls,) + args + tuple(kwargs.items()) 
      try: 
       inst = cache.get(key, None) 
      except TypeError: 
       # Can't cache this set of arguments 
       inst = key = None 
      if inst is None: 
       inst = klass.__new__(klass, *args, **kwargs) 
       inst.__init__(*args, **kwargs) 
       if key is not None: 
        cache[key] = inst 
      return inst 

    return wrapper 

작은 테스트 스위트는 다음과 revals :

>>> @cachedClass 
... class Foo: 
...  pass 
>>> f1 = Foo() 
>>> f2 = Foo() 
>>> f1 is f2 
True 
>>> Foo 
<class 'cache.Foo'> 
>>> type(f1) 
<class 'cache.Foo'> 
>>> isinstance(f1, Foo) 
False 

내가 마지막 표현 True를 반환 할 것으로 예상. 내가 뭘 놓치고 있니?

+0

저는 파이썬 2.7을 사용하고 있습니다. 'True'를 얻습니다. 그러나 인터프리터는'type (f1)'을 실행할 때''를 반환합니다. – HFBrowning

+2

@HFBrowning 왜냐하면'class Foo : pass'는 파이썬 2의 구식 클래스이기 때문입니다. – vaultah

답변

3
@cachedClass 
class Foo: 
    pass 

Foo 이름 wrapper 클래스 cachedClass의 반환 값을 할당

class Foo: 
    pass 

Foo = cachedClass(Foo) 

의미 적으로 동등하다.

wrapper 사본 Foo 년대 __name__ 다른 던더 속성과 함께 속성 때문에 wrapper 클래스 Foo 같은 보이는 functool.wraps 장식 차례입니다.

당신은 @wraps 줄을 제거하고 인쇄 할 경우

print(type(f1), Foo, type(f1) is Foo, sep=', ') 

당신은 f1 원래 Foo 클래스의 인스턴스 인 것을 볼 수 있지만, Foo이름 이제 wrapper 클래스를 의미하고

<class '__main__.Foo'>, <class '__main__.cachedClass.<locals>.wrapper'>, False 
+0

이제 감사합니다! 나는 어쨌든'isinstance'가'__class__'보다는'__name__' 만 체크한다고 생각했을 것입니다. 래퍼를 진정으로 투명하게 만드는 간단한 방법이 있습니까? – polwel

+0

@polwel 아무도 내가 아는 바 없다. 원래 클래스를 반환해야합니다. – vaultah