Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does isinstance() return False in this case?

I would like to write a decorator that allows memoiziation of a constructor. When I construct a class, I want the object returned from cache when possible.

The following code has been adapted from 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

A small test suite revals the following:

>>> @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

I expected that the last expression would return True. What am I missing?

like image 517
polwel Avatar asked Jul 31 '26 09:07

polwel


1 Answers

@cachedClass
class Foo:
    pass

is semantically equivalent to

class Foo:
    pass

Foo = cachedClass(Foo)

The Foo name is assigned the return value of cachedClass, which is the wrapper class.

wrapper is in turn decorated by functool.wraps that copies Foo's __name__ attribute along with some other dunder attributes, so the wrapper class looks like Foo.

If you remove the @wraps line and print

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

you'll see that the f1 is an instance of the original Foo class, but the Foo name now refers to the wrapper class, and they are different objects:

<class '__main__.Foo'>, <class '__main__.cachedClass.<locals>.wrapper'>, False
like image 144
vaultah Avatar answered Aug 02 '26 23:08

vaultah



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!