[英]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 typesTypeError: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
. 这意味着
Foo
是Decorator
类的实例。 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.