测试对象的类型 通常是python 中的一种反模式。在某些情况下,测试对象的 “鸭子类型” 是有意义的,例如:
hasattr(some_var, "username")
但即使这样也是不可取的,例如,即使包装器使用 __getattribute__ 的一些魔法来正确代理属性,该表达式也有可能返回 false 的原因。
通常更倾向于允许变量只采用一个抽象类型,并且可能是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,因为该值存在于类创建时间。
编辑:正如 cmets 中所指出的,以上仅适用于一些简单类型,如果您需要在目标对象上代理更精细的属性(例如方法),请参阅以下答案:Python - Faking Type Continued