【问题标题】:Why does isinstance() return False in this case?为什么 isinstance() 在这种情况下返回 False?
【发布时间】:2018-04-26 10:29:42
【问题描述】:

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

以下代码改编自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。我错过了什么?

【问题讨论】:

  • 我使用的是 Python 2.7,我确实收到了 True。但是,当我运行 type(f1) 时,解释器也会返回 &lt;type 'instance'&gt;
  • @HFBrowning 因为class Foo: pass 是 Python 2 中的旧式类。

标签: python python-3.x constructor memoization


【解决方案1】:
@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 类的一个实例,但Foo name 现在引用wrapper 类,它们是不同的对象:

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

【讨论】:

  • 现在很明显了,谢谢!我一定认为isinstance 只检查__name__ 而不是__class__。有没有一种简单的方法可以让包装器真正透明?
猜你喜欢
  • 2016-03-02
  • 1970-01-01
  • 2014-09-12
  • 2018-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多