Тестирование типа объекта обычно является антипаттерном в python.В некоторых случаях имеет смысл проверить «тип утки» объекта, что-то вроде:
hasattr(some_var, "username")
Но даже это нежелательно, например, есть причины, по которым это выражение может возвращатьсяfalse, даже если оболочка использует магию с __getattribute__
для правильной передачи атрибута через прокси.
Обычно предпочтительно, чтобы переменные принимали только один абстрактный тип и, возможно, None
.Различное поведение, основанное на разных входных данных, должно быть достигнуто путем передачи необязательно типизированных данных в разные переменные.Вы хотите сделать что-то вроде этого:
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")
Конечно, все это предполагает, что у вас есть некоторый уровень контроля над кодом, который выполняет проверку типа.Предположим, это не так.для того, чтобы функция isinstance () вернула true, класс должен появиться в базах экземпляра, или класс должен иметь __instancecheck__
.Поскольку вы не контролируете ни одну из этих вещей для класса, вы должны прибегнуть к некоторым махинациям в этом случае.Сделайте что-то вроде этого:
def wrap_user(instance):
class wrapped_user(type(instance)):
__metaclass__ = type
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()
То, что мы делаем, - это динамическое создание нового класса в тот момент, когда нам нужно обернуть экземпляр и фактически наследовать от обернутого объекта __class__
.Мы также переходим к дополнительным проблемам, связанным с переопределением __metaclass__
, в случае, если у оригинала есть некоторые дополнительные поведения, с которыми мы фактически не хотим сталкиваться (например, ищем таблицу базы данных с определенным именем класса).Приятным удобством этого стиля является то, что нам никогда не нужно создавать какие-либо атрибуты экземпляра в классе-обертке, нет self.wrapped_object
, поскольку это значение присутствует во время создания класса .
Редактировать: Как указано в комментариях, вышеупомянутое работает только для некоторых простых типов, если вам нужно проксировать более сложные атрибуты на целевом объекте (скажем, методы), тогда смотрите следующий ответ: Python - тип подделки продолжение