Python isinstance
函数如何在内部工作?我可以做些什么来改变它的结果,比如在类中定义一个特殊的函数还是什么?这是我的用例:
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
行为几乎就像mixin一样,除了混音在这里不合适。有什么方法可以让上面的代码工作吗?我还应该注意isinstance
行也会出现以下错误:
isinstance(f,Foo)
TypeError:isinstance()arg 2必须是类型或类型元组
答案 0 :(得分:5)
以下内容如何:
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)
使用上面的代码:
isinstance(f, Foo)
有效; f()
调用deco方法,然后转发到原始方法。基本想法是确保装饰的Foo
仍然是一个类,并确保装饰的Foo
是原始的{em>子类 { {1}}。
P.S。这一切的目的对我来说并不完全清楚;可能是元类是实现你想要做的事情的更好方法。
答案 1 :(得分:1)
问题是你的例子中的Foo
不是一个类。
此代码:
@Decorator
class Foo:
pass
相当于:
class Foo:
pass
Foo = Decorator(Foo)
这意味着Foo
是类Decorator
的实例。由于Foo
不是clas或type,isinstance
会抱怨。
答案 2 :(得分:0)
在装饰类时,装饰的返回值也常常是有用的或可取的;实现这一目标最明显的方法是使用装饰器构造并直接返回一个新类。
该功能已由元类处理;事实上,元类比装饰器更强大,因为你甚至可以在构造一个装饰类之前描述新类。
另一个选择是返回传入的同一个对象;但有一些变化。这对装饰器来说更好用,因为它在嵌套装饰器时效果很好。由于您在使用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
答案 3 :(得分:-1)
如果Foo
在没有调用Foo
的情况下返回,则无法获取该对象的类型。
isinstance
抱怨它的第二个参数,因为它是一个实例 - 在你的Decorated
案例中。虽然你认为Foo
就像一个类,但实际上它只是一个可调用的对象而且它不是一个类。
也许下一个会帮助您重新思考/解决您的问题:
>>> isinstance(f, Foo._decorated)
True