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

3
我想编写一个装饰器,允许对构造函数进行备忘录。当我构造一个类时,如果可能的话,我希望从缓存中返回对象。
以下代码已经改编自这里
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。我错过了什么吗?

我正在使用Python 2.7,我确实得到了True。然而,当我运行type(f1)时,解释器也返回<type 'instance'> - HFBrowning
2
@HFBrowning 因为 class Foo: pass 是 Python 2 中的旧式类。 - vaultah
1个回答

3
@cachedClass
class Foo:
    pass

语义上等同于

class Foo:
    pass

Foo = cachedClass(Foo)
Foo名称被分配为cachedClass的返回值,该返回值是wrapper类。 wrapper类接着被functool.wraps装饰,它复制了Foo__name__属性以及一些其他的dunder属性,因此wrapper类看起来像Foo
如果您删除@wraps行并打印
print(type(f1), Foo, type(f1) is Foo, sep=', ')

你会看到f1是原始Foo类的一个实例,但Fooname现在指向wrapper类,它们是不同的对象:

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

现在很明显,谢谢!我不知怎么会认为isinstance只检查__name__而不是__class__。有没有一种简单的方法使包装器真正透明? - polwel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接