Object type testing is usually antipattern in python. In some cases, it makes sense to test the "type of duck" object, something like:
hasattr(some_var, "username")
But even this is undesirable, for example, there are reasons why this expression can return false, although the shell uses some magic with __getattribute__ to correctly proxy the attribute.
It is usually preferred that variables accept only one abstract type and possibly None . Different behaviors based on different inputs must be achieved by passing optionally typed data in different variables. You want to do something like this:
def dosomething(some_user=None, some_otherthing=None): if some_user is not None:
Of course, all of this assumes that you have some level of control over the code that performs type checking. Suppose this is not the case. for "isinstance ()" to return true, the class should appear in the instance database, or the class must have __instancecheck__ . Since you do not control any of these things for the class, you need to resort to some fraud on the instance. Do something like this:
def wrap_user(instance): class wrapped_user(type(instance)): __metaclass__ = type def __new__(cls): pass def __init__(self): pass def __getattribute__(self, attr): self_dict = object.__getattribute__(type(self), '__dict__') if attr in self_dict: return self_dict[attr] return getattr(instance, attr) def extra_feature(self, foo): return instance.username + foo
What we do is create a new class dynamically at the time when we need to wrap the instance and actually inherit from the wrapped __class__ object. We also move on to the additional __metaclass__ override problem if the original had some additional behavior that we actually don't encounter (for example, finding a database table with a specific class name). A good convenience of this style is that we never need to create instance attributes in the wrapper class, there is no self.wrapped_object , since this value is present at the time the class is created.
Edit: as noted in the comments, the above only works for some simple types, if you need to proxy more complex attributes of the target object (say, methods), and then see the following answer: Python - Fake Type Continued