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

时间:2017-11-13 16:47:32

标签: python python-3.x constructor memoization

我想写一个装饰器,它允许构造函数的memoiziation。当我构造一个类时,我想尽可能从缓存返回对象。

以下代码改编自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 个答案:

答案 0 :(得分:3)

@cachedClass
class Foo:
    pass

在语义上等同于

class Foo:
    pass

Foo = cachedClass(Foo)

Foo名称的返回值为cachedClass,即{。}}  wrapper上课。

wrapper依次由functool.wraps修饰,复制Foo的{​​{1}}属性以及其他一些dunder属性,因此__name__看起来像<{1}}

如果您删除wrapper行并打印

Foo

您会看到@wraps是原始print(type(f1), Foo, type(f1) is Foo, sep=', ') 类的实例,但f1 名称现在引用{{1} } class,它们是不同的对象:

Foo