测试对象的 类型 通常是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
,因为它在类创建时 就存在,所以不需要。