如何使用 Python 伪造类型 [英] How to fake type with Python

查看:17
本文介绍了如何使用 Python 伪造类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近在 Python 中围绕一些 ORM 文档对象开发了一个名为 DocumentWrapper 的类,以透明地向其添加一些功能,而无需以任何方式更改其接口.

I recently developed a class named DocumentWrapper around some ORM document object in Python to transparently add some features to it without changing its interface in any way.

我对此只有一个问题.假设我有一些 User 对象包裹在其中.调用 isinstance(some_var, User) 将返回 False 因为 some_var 确实是 DocumentWrapper 的一个实例.

I just have one issue with this. Let's say I have some User object wrapped in it. Calling isinstance(some_var, User) will return False because some_var indeed is an instance of DocumentWrapper.

有没有办法在 Python 中伪造一个对象的类型以具有相同的调用返回 True?

Is there any way to fake the type of an object in Python to have the same call return True?

推荐答案

测试对象的类型通常是python中的一种反模式.在某些情况下,测试对象的鸭子类型" 是有意义的,例如:

Testing the type of an object is usually an antipattern in python. In some cases it makes sense to test the "duck type" of the object, something like:

hasattr(some_var, "username")

但即使这样也是不可取的,例如,该表达式可能返回 false 是有原因的,即使包装器使用带有 __getattribute__ 的一些魔法来正确代理属性.

But even that's undesirable, for instance there are reasons why that expression might return false, even though a wrapper uses some magic with __getattribute__ to correctly proxy the attribute.

通常首选允许变量只采用一个抽象类型,并且可能None.应该通过在不同变量中传递可选类型的数据来实现基于不同输入的不同行为.你想做这样的事情:

It's usually preferred to allow variables only take a single abstract type, and possibly None. Different behaviours based on different inputs should be achieved by passing the optionally typed data in different variables. You want to do something like this:

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__.由于您无法控制课程中的任何一项,因此您必须对实例采取一些恶作剧.做这样的事情:

Of course, this all assumes you have some level of control of the code that is doing the type checking. Suppose it isn't. for "isinstance()" to return true, the class must appear in the instance's bases, or the class must have an __instancecheck__. Since you don't control either of those things for the class, you have to resort to some shenanigans on the instance. Do something like this:

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,因为该值在类创建时存在.

What we're doing is creating a new class dynamically at the time we need to wrap the instance, and actually inherit from the wrapped object's __class__. We also go to the extra trouble of overriding the __metaclass__, in case the original had some extra behaviors we don't actually want to encounter (like looking for a database table with a certain class name). A nice convenience of this style is that we never have to create any instance attributes on the wrapper class, there is no self.wrapped_object, since that value is present at class creation time.

正如评论中所指出的,以上仅适用于一些简单的类型,如果您需要在目标对象上代理更复杂的属性(例如,方法),请参阅以下答案:Python - 继续伪造类型

As pointed out in comments, the above only works for some simple types, if you need to proxy more elaborate attributes on the target object, (say, methods), then see the following answer: Python - Faking Type Continued

这篇关于如何使用 Python 伪造类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆