I recently developed a class named DocumentWrapper
around some ORM document object in Python to transparently add some features to it without changing its interface in any way.
I just have one issue with this. Let's say I have some User
object wrapped in it. Calling isinstance(some_var, User)
will return False
because some_var
indeed is an instance of DocumentWrapper
.
Is there any way to fake the type of an object in Python to have the same call return True
?
The best way is to inherit DocumentWrapper from the User itself, or mix-in pattern and doing multiple inherintance from many classes
You can also fake isinstance() results by manipulating
obj.__class__
but this is deep level magic and should not be done.You can use the
__instancecheck__
magic method to override the defaultisinstance
behaviour:This is only if you want your object to be a transparent wrapper; that is, if you want a
DocumentWrapper
to behave like aUser
. Otherwise, just expose the wrapped class as an attribute.This is a Python 3 addition; it came with abstract base classes. You can't do the same in Python 2.
Testing the type of an object is usually an antipattern in python. In some cases it makes sense to test the "duck type" of the object, something like:
But even that's undesirable, for instance there are reasons why that expression might return false, even though a wrapper uses some magic with
__getattribute__
to correctly proxy the attribute.It's usually preferred to allow variables only take a single abstract type, and possibly
None
. Different behaviours based on different inputs should be achieved by passing the optionally typed data in different variables. You want to do something like this:Of course, this all assumes you have some level of control of the code that is doing the type checking. Suppose it isn't. for "isinstance()" to return true, the class must appear in the instance's bases, or the class must have an
__instancecheck__
. Since you don't control either of those things for the class, you have to resort to some shenanigans on the instance. Do something like this:What we're doing is creating a new class dynamically at the time we need to wrap the instance, and actually inherit from the wrapped object's
__class__
. We also go to the extra trouble of overriding the__metaclass__
, in case the original had some extra behaviors we don't actually want to encounter (like looking for a database table with a certain class name). A nice convenience of this style is that we never have to create any instance attributes on the wrapper class, there is noself.wrapped_object
, since that value is present at class creation time.Edit: As pointed out in comments, the above only works for some simple types, if you need to proxy more elaborate attributes on the target object, (say, methods), then see the following answer: Python - Faking Type Continued
Override
__class__
in your wrapper classDocumentWrapper
:This way no modifications to the wrapped class
User
are needed.Python Mock does the same (see mock.py:612 in mock-2.0.0, couldn't find sources online to link to, sorry).
It sounds like you want to test the type of the object your
DocumentWrapper
wraps, not the type of theDocumentWrapper
itself. If that's right, then the interface toDocumentWrapper
needs to expose that type. You might add a method to yourDocumentWrapper
class that returns the type of the wrapped object, for instance. But I don't think that making the call toisinstance
ambiguous, by making it return True when it's not, is the right way to solve this.Here is a solution by using metaclass, but you need to modify the wrapped classes: