Prueba de la tipo de un objeto es por lo general un antipattern en python. En algunos casos, tiene sentido para probar el "tipo de pato" del objeto, algo así como:
hasattr(some_var, "username")
Pero incluso eso es indeseable, por ejemplo, hay razones por las que la expresión puede devolver false, a pesar de que un envoltorio usa algo de magia con __getattribute__
para proxy correcto del atributo.
Por lo general, se prefiere permitir que las variables solo tomen un solo tipo abstracto, y posiblemente None
. Se deben lograr diferentes comportamientos basados en diferentes entradas pasando los datos opcionalmente tipados en diferentes variables.¿Quieres hacer algo como esto:
def dosomething(some_user=None, some_otherthing=None):
if some_user is not None:
#do the "User" type action
elif some_otherthing is not None:
#etc...
else:
raise ValueError("not enough arguments")
Por supuesto, todo esto supone que tiene un cierto nivel de control del código que está haciendo la comprobación de tipos. Supongamos que no lo es. para que "isinstance()" devuelva verdadero, la clase debe aparecer en las bases de la instancia, o la clase debe tener un __instancecheck__
. Como no controlas ninguna de esas cosas para la clase, tienes que recurrir a algunos chanchullos en la instancia. Hacer algo como esto:
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 # or whatever
return wrapped_user()
Lo que estamos haciendo es crear una nueva clase de forma dinámica en el tiempo que necesitamos para envolver la instancia, y de hecho de heredar de __class__
el objeto envuelto. También nos enfrentamos al problema adicional de anular el __metaclass__
, en caso de que el original tuviera algunos comportamientos adicionales que realmente no queremos encontrar (como buscar una tabla de base de datos con un cierto nombre de clase). Una buena conveniencia de este estilo es que nunca tenemos que crear ningún atributo de instancia en la clase contenedora, no hay self.wrapped_object
, ya que ese valor está presente en tiempo de creación de clase.
Edit: Como se ha señalado en los comentarios, lo anterior sólo funciona para algunos tipos simples, si necesita proxy de atributos más elaboradas en el objeto de destino, (por ejemplo, métodos), a continuación, ver la siguiente respuesta: Python - Faking Type Continued
herencia múltiple? – JBernardo
'isinstance (some_var.user, User)'? ¿Qué estás tratando de hacer? –
Solo trato de tener un contenedor transparente, que se comporta * exactamente * como la clase envuelta. Incluyendo con isinstance. La herencia múltiple no es la solución, al menos porque el Usuario es solo una de las muchas clases que envuelve DocumentWrapper. (No tengo control sobre estas clases, no puedo cambiar su árbol de herencia.) – Pierre