2024-04-27 01:16:48 发布
网友
最近,我围绕Python中的某个ORM文档对象开发了一个名为DocumentWrapper的类,以便在不以任何方式更改其接口的情况下透明地向其添加一些特性。
DocumentWrapper
我只是有一个问题。假设我有一些User对象包装在里面。调用isinstance(some_var, User)将返回False,因为some_var确实是DocumentWrapper的实例。
User
isinstance(some_var, User)
False
some_var
在Python中,是否有任何方法可以伪造对象的类型,使其具有相同的调用返回True?
True
在python中,测试对象的类型通常是反模式。在某些情况下,测试对象的“duck type”是有意义的,例如:
hasattr(some_var, "username")
但即使这是不可取的,例如,也有一些原因说明了为什么该表达式可能返回false,即使包装器使用__getattribute__的某种魔力来正确代理属性。
__getattribute__
通常更倾向于允许变量只接受一个抽象类型,并且可能是None。基于不同输入的不同行为应该通过在不同变量中传递可选类型的数据来实现。你想这样做:
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__。既然你不能控制课堂上的任何一件事,你就必须在这个例子中使用一些恶作剧。做这样的事:
__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__的额外问题,以防原始文件有一些我们实际上不想遇到的额外行为(比如寻找具有特定类名的数据库表)。这种样式的一个很好的便利之处是,我们不必在包装类上创建任何实例属性,因为该值出现在类创建时间中。
__class__
__metaclass__
编辑:正如注释中所指出的,上面的方法只适用于一些简单的类型,如果您需要代理目标对象上更详细的属性(比如,方法),那么请看下面的答案:Python - Faking Type Continued
您可以使用__instancecheck__magic方法覆盖默认的isinstance行为:
isinstance
@classmethod def __instancecheck__(cls, instance): return isinstance(instance, User)
只有当你想让你的对象成为一个透明的包装器,也就是说,如果你想让一个DocumentWrapper表现得像一个User。否则,只需将包装好的类作为属性公开。
这是Python 3的一个附加项;它附带了抽象基类。在Python 2中不能这样做。
重写包装类中的__class__:
class DocumentWrapper(object): @property def __class__(self): return User >>> isinstance(DocumentWrapper(), User) True
这样就不需要修改包装类User。
Python Mock也有同样的功能(请参见Mock-2.0.0中的Mock.py:612,很抱歉,找不到联机链接的源代码)。
在python中,测试对象的类型通常是反模式。在某些情况下,测试对象的“duck type”是有意义的,例如:
但即使这是不可取的,例如,也有一些原因说明了为什么该表达式可能返回false,即使包装器使用
__getattribute__
的某种魔力来正确代理属性。通常更倾向于允许变量只接受一个抽象类型,并且可能是
None
。基于不同输入的不同行为应该通过在不同变量中传递可选类型的数据来实现。你想这样做:当然,这一切都假设您对执行类型检查的代码具有某种程度的控制。如果不是,则“isinstance()”若要返回true,该类必须出现在实例的基中,或者该类必须具有
__instancecheck__
。既然你不能控制课堂上的任何一件事,你就必须在这个例子中使用一些恶作剧。做这样的事:我们所做的是在需要包装实例时动态地创建一个新类,并从包装对象的
__class__
继承。我们还要处理重写__metaclass__
的额外问题,以防原始文件有一些我们实际上不想遇到的额外行为(比如寻找具有特定类名的数据库表)。这种样式的一个很好的便利之处是,我们不必在包装类上创建任何实例属性,因为该值出现在类创建时间中。编辑:正如注释中所指出的,上面的方法只适用于一些简单的类型,如果您需要代理目标对象上更详细的属性(比如,方法),那么请看下面的答案:Python - Faking Type Continued
您可以使用
__instancecheck__
magic方法覆盖默认的isinstance
行为:只有当你想让你的对象成为一个透明的包装器,也就是说,如果你想让一个
DocumentWrapper
表现得像一个User
。否则,只需将包装好的类作为属性公开。这是Python 3的一个附加项;它附带了抽象基类。在Python 2中不能这样做。
重写包装类中的
__class__
:这样就不需要修改包装类
User
。Python Mock也有同样的功能(请参见Mock-2.0.0中的Mock.py:612,很抱歉,找不到联机链接的源代码)。
相关问题 更多 >
编程相关推荐