代码之家  ›  专栏  ›  技术社区  ›  polwel

在这种情况下,为什么isinstance()返回False?

  •  3
  • polwel  · 技术社区  · 6 年前

    我想写一个允许记忆构造函数的装饰器。在构造类时,我希望尽可能从缓存中返回对象。

    以下代码改编自 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
    

    >>> @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 . 我错过了什么?

    1 回复  |  直到 6 年前
        1
  •  3
  •   vaultah    6 年前
    @cachedClass
    class Foo:
        pass
    

    在语义上等价于

    class Foo:
        pass
    
    Foo = cachedClass(Foo)
    

    这个 Foo name被分配返回值 cachedClass ,这是 wrapper

    包装器 依次由 functool.wraps 那个复制品 __name__ 属性以及其他dunder属性,因此 包装器 喜欢 .

    @wraps 线条和打印

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

    你会看到 f1 是原始的实例 类,但 名称 现在指的是 类,它们是不同的对象:

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