3

Pythonisinstance函数在内部是如何工作的?我可以做些什么来改变它的结果,比如在一个类中定义一个特殊的函数之类的吗?这是我的用例:

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行为几乎就像一个混合,除了混合在这里不合适。有什么办法可以使上面的代码工作吗?我还应该注意,该isinstance行还给出了以下错误:

    isinstance(f, Foo)
TypeError: isinstance() arg 2 must be a type or tuple of types

4

4 回答 4

6

以下情况如何:

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()调用修饰的方法,然后转发到原始方法。

基本思想是确保被装饰Foo物仍然是一个类,并且还确保被装饰Foo物是原始的子类Foo

PS这一切的目的对我来说并不完全清楚;元类可能是实现您想要做的事情的更好方法。

于 2011-09-22T12:59:43.227 回答
1

问题是Foo在你的例子中不是一个类。

这段代码:

@Decorator
class Foo:
    pass

相当于:

class Foo:
    pass
Foo = Decorator(Foo)

这意味着这Foo是 class 的一个实例Decorator。因为Foo不是类或类型,所以isinstance抱怨。

于 2011-09-22T13:00:23.563 回答
0

当装饰一个类时,装饰的返回值也是类型通常是有用的或可取的;实现这一点的最明显方法是让装饰器构造并直接返回一个新类。

该功能已经由元类处理;事实上,元类比装饰器更强大一点,因为你可以在装饰类构建之前描述新类。

另一种选择是返回传入的相同对象;但有一些变化。这对装饰器来说是一个更好的用途,因为它在嵌套装饰器时效果很好。由于您正在修改使用时的行为Foo(),因此您可能想要修改 Foo's __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
于 2011-09-22T13:24:36.540 回答
-1

您无法获得Foo不调用就返回的对象的类型Foo

isinstance抱怨它的第二个参数,因为它是一个实例 - 在你的情况下是Decorated. 虽然你认为Foo它像一个类,但实际上它只是一个可调用对象而不是一个类。

也许下一个将帮助您重新思考/解决您的问题:

>>> isinstance(f, Foo._decorated)
True
于 2011-09-22T13:05:02.283 回答