简体   繁体   English

与装饰员一起使“实例”工作

[英]Making 'isinstance' work with decorators

How does the Python isinstance function work internally? Python isinstance函数如何在内部工作? Is there anything I can do to alter its results, like define a special function inside a class or something? 我可以做些什么来改变它的结果,例如在类之内定义一个特殊的函数吗? Here's my use case: 这是我的用例:

class Decorator:
    def __init__(self, decorated):
        self._decorated = decorated

    def __call__(self):
        return self._decorated()

@Decorator
class Foo:
    pass

f = Foo()

# How can I make this be true?
isinstance(f, Foo)

Decorator acts almost like a mixin, except a mixing wouldn't be appropriate here. Decorator行为几乎像一个混合器,只是混合在这里不合适。 Is there any way I can make the above code work? 有什么办法可以使上面的代码起作用? I should also note that the isinstance line also gives the following error: 我还要注意, isinstance行还给出以下错误:

isinstance(f, Foo) isinstance(f,Foo)
TypeError: isinstance() arg 2 must be a type or tuple of types TypeError:isinstance()arg 2必须是一个类型或类型的元组

How about the following: 怎么样:

def Decorator(decorated):
    class Dec(decorated):
        def __call__(self):
            print 'in decorated __call__'
            return decorated.__call__(self)
    return Dec

@Decorator
class Foo(object):
    def __call__(self):
        print 'in original __call__'

f = Foo()

# How can I make this be true?
print isinstance(f, Foo)

With the above code: 使用上面的代码:

  • isinstance(f, Foo) works; isinstance(f, Foo)起作用;
  • f() calls the decorated method which then forwards to the original method. f()调用修饰的方法,然后将其转发到原始方法。

The basic idea is to make sure that the decorated Foo is still a class, and to also make sure that the decorated Foo is a subclass of the original Foo . 基本思想是确保装饰的Foo仍然是一个类,并且还确保装饰的Foo是原始Foo子类

PS The purpose of all this is not entirely clear to me; PS:所有这一切的目的对我来说都不是很清楚。 it might be that metaclasses are a better way to achieve what you're trying to do. 元类可能是实现您要执行的操作的更好方法。

The problem is that Foo in your example isn't a class. 问题在于您的示例中的Foo不是类。

This code: 这段代码:

@Decorator
class Foo:
    pass

is equivalent to: 等效于:

class Foo:
    pass
Foo = Decorator(Foo)

Which means that Foo is an instance of class Decorator . 这意味着FooDecorator类的实例。 Because Foo is not a clas or type, isinstance complains. 因为Foo不是分类或类型,所以isinstance抱怨。

When decorating a class, it's often useful or desirable to for the decorated return value to also be type; 装饰一个类时,装饰后的返回值也要类型化通常是有用或期望的。 The most obvious way of achieving this is to have the decorator construct and return a new class directly. 实现此目的最明显的方法是构造装饰器并直接返回一个新类。

That functionality is already handled by metaclasses; 该功能已经由元类处理; In fact, metaclasses are a bit more powerful than decorators, since you get to describe the new class before a decorated class has even been constructed. 实际上,元类比装饰器要强大一些,因为您可以在构造装饰类之前就描述新类。

Another option is to return the same object that was passed in; 另一个选择是返回传入的对象。 but with some changes. 但有一些变化。 That's a better use for decorators, since it works well when you nest decorators. 这对于装饰器是更好的用法,因为在嵌套装饰器时效果很好。 Since you're modifying the behavior when Foo() is used, then you probably want to modify Foo's __init__ , which might look like this: 由于要在使用Foo()时修改行为,因此您可能想修改Foo的__init__ ,它可能像这样:

>>> def Decorator(cls):
...     assert isinstance(cls, type)
...     try:
...         old_init = cls.__init__.im_func
...     except AttributeError:
...         def old_init(self): pass
...     def new_init(self):
...         # do some clever stuff:
...         old_init(self)
...     cls.__init__ = new_init
...     return cls
... 
>>> @Decorator
... class Foo(object):
...     def __init__(self): pass
... 
>>> @Decorator
... class Bar(object):
...     pass
... 
>>> f = Foo()
>>> isinstance(f, Foo)
True

You can't get type of the object that Foo returns without calling Foo . 如果不调用Foo ,就无法获得Foo返回的对象的类型。

isinstance complains about its second argument because it is an instance - in you case instance of Decorated . isinstance抱怨它的第二个参数,因为它是一个实例-在您的实例中为Decorated Although you think of Foo like a class but actually it is just a callable object and it is not a class. 尽管您将Foo类,但实际上它只是一个可调用的对象,而不是类。

Maybe the next will help you to rethink/solve your problem: 也许下一个将帮助您重新考虑/解决您的问题:

>>> isinstance(f, Foo._decorated)
True

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM