制作“isinstance”与装饰者合作

发布于 2024-12-05 23:54:09 字数 604 浏览 5 评论 0原文

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 必须是类型或类型元组

How does the Python isinstance function work internally? 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. 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(f, Foo)
TypeError: isinstance() arg 2 must be a type or tuple of types

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

永言不败 2024-12-12 23:54:09

下面的怎么样:

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 我并不完全清楚这一切的目的;元类可能是实现您想要做的事情的更好方法。

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;
  • f() calls the decorated method which then forwards to the original method.

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.

P.S. The purpose of all this is not entirely clear to me; it might be that metaclasses are a better way to achieve what you're trying to do.

幻想少年梦 2024-12-12 23:54:09

问题是您的示例中的 Foo 不是一个类。

此代码:

@Decorator
class Foo:
    pass

相当于:

class Foo:
    pass
Foo = Decorator(Foo)

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

The problem is that Foo in your example isn't a class.

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. Because Foo is not a clas or type, isinstance complains.

生寂 2024-12-12 23:54:09

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

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

另一种选择是返回传入的同一对象;但有一些变化。这对装饰器来说是更好的用途,因为当您嵌套装饰器时它效果很好。由于您要修改使用 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

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:

>>> 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
难如初 2024-12-12 23:54:09

如果不调用 Foo,则无法获取 Foo 返回的对象的类型。

isinstance 抱怨它的第二个参数,因为它是一个实例 - 在你的例子中是 Decolated 的实例。虽然您将 Foo 视为一个类,但实际上它只是一个可调用对象,而不是一个类。

也许接下来会帮助您重新思考/解决您的问题:

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

You can't get type of the object that Foo returns without calling Foo.

isinstance complains about its second argument because it is an instance - in you case instance of Decorated. Although you think of Foo like a class but actually it is just a callable object and it is not a class.

Maybe the next will help you to rethink/solve your problem:

>>> isinstance(f, Foo._decorated)
True
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文