如何使用Python伪造类型
我最近DocumentWrapper
在Python中开发了一个围绕某些ORM文档对象命名的类,以透明地向其中添加一些功能,而不用任何方式更改其接口。
我对此只有一个问题。假设我User
包裹了一些物体。呼叫isinstance(some_var,
User)
将返回,False
因为some_var
确实是的一个实例DocumentWrapper
。
有没有办法伪造Python中的对象类型以具有相同的调用返回True
?
-
测试对象的 类型 通常是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
,因为它在
类创建时 就存在,所以不需要。