Why does isinstance() return False in this case?… here is a solution to the problem.
Why does isinstance() return False in this case?
I want to write a decorator that allows memory constructors. When I construct a class, I want to return objects from the cache whenever possible.
The following code is 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 reevaluates 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 expect the last expression to return True
. What am I missing?
Solution
@cachedClass
class Foo:
pass
Semantically equivalent to
class Foo:
pass
Foo = cachedClass(Foo)
The Foo
name is given the return value of cachedClass
, which is
Wrapper
class.
Wrapper
is decorated by functool.wraps, which duplicates
Foo's
__name__
attribute and some other dunder attributes, so the wrapper
class looks like Foo
.
If you delete @wraps
line and print it
print(type(f1), Foo, type(f1) is Foo, sep=', ')
You’ll see that f1
is an instance of the original Foo class, but the Foo
name now refers to
the wrapper
class, which are different objects:
<class '__main__. Foo'>, <class '__main__.cachedClass.<locals>.wrapper'>, False