在Python中扩展被装饰的类

1 投票
3 回答
705 浏览
提问于 2025-04-16 00:58

有没有办法扩展一个已经应用了装饰器的类呢?比如说:

@someDecorator
Class foo(object):
  ...
  ...

Class bar(foo):
  ...
  ...

理想情况下,bar 这个类不应该受到装饰器的影响,但我首先想知道这是否可能。目前我遇到了一个非运行时的错误:

“类型错误:调用元类基类时出错,函数的第一个参数必须是代码,而不是字符串。”

有什么建议吗?

3 个回答

1

如果你在寻找一个不同于最佳答案的方法,我发现对我来说最好的办法是在类装饰器里面装饰 __init__ 方法。比如说:

def some_decorator(cls):
    def decorate_init(func):
        def decorated(*args, **kwargs):
            func(*args, **kwargs) # Run __init__
            instance = args[0]
            # Do whatever you need with the newly constructed instance
        return decorated
    cls.__init__ = decorated_init(cls.__init__)
    return cls
2

是的,这种情况是可能的,只要@someDecorator确实返回了一个类。类装饰器的作用是接收一个类作为参数,并且通常应该返回一个类,除非你在做一些非常特别的事情。

在这个例子中,foo将会和@someDecorator返回的内容绑定在一起。

这个装饰器是不是返回了其他东西?比如一个str(字符串)?

0

正如Matt所说,你的装饰器没有正常工作。每当你让装饰器正常工作时(可以做一些测试,甚至直接复制粘贴到控制台进行即时测试):

有效的装饰器返回的就是你的类“foo”——如果你使用装饰器语法,就无法访问装饰器应用之前的内容。

不过,在Python中,装饰器其实是一种语法糖,它可以把你声明的函数或类替换成经过装饰器处理后返回的内容。因此,下面这两种写法是等价的:

@someDecorator
class foo(object):
   pass

class foo(object):
   pass
foo = someDecorator(foo)

所以,你可以通过以下方式在应用装饰器之前扩展一个类:

class foo(object):
   pass
class bar(foo):
   pass

foo = someDecorator(foo)

撰写回答