在类中定义一个装饰器,且可在类定义中使用

5 投票
1 回答
909 浏览
提问于 2025-04-16 10:55

我正在尝试在Python中实现一个可以继承的“子命令”系统。我的预期用法大概是这样的:

from command import Command
import sys

class MyCommand(Command):
    @Command.subcommand
    def foo(self):
        print "this can be run as a subcommand"

    def bar(self):
        print "but this is a plain method and isn't exposed to the CLI"

MyCommand()(*sys.argv)

# at the command line, the user runs "mycommand.py foo"

我把Command.subcommand实现成了一个静态方法,一切都运行得很好,直到我尝试给父类添加一个子命令,这时出现了TypeError: 'staticmethod' object is not callable的错误。回想起来,很明显这个方法是行不通的:

class Command(object):
    @staticmethod
    def subcommand(method):
        method.is_subcommand = True

        return method

    @subcommand
    def common(self):
        print "this subcommand is available to all child classes"

到目前为止,我找到的唯一替代方案是把subcommand装饰器放在父类外面,然后在类定义完成后再注入它。

def subcommand(method):
    method.is_subcommand = True

    return method

class Command(object):
    @subcommand
    def common(self):
        print "this subcommand is available to all child classes"

Command.subcommand = staticmethod(subcommand)
del subcommand

不过,作为一个在装饰器出现之前就没用过Python的人,这让我觉得很麻烦。有没有更优雅的方法来实现这个呢?

1 个回答

5

我想到这个问题有两种解决方案。最简单的办法是在你在父类中用完这个方法之后把它改成静态方法:

class Command(object):
    def subcommand(method): # Regular function in class definition scope.
        method.is_subcommand = True

        return method

    @subcommand
    def common(self):
        print "this subcommand is available to all child classes"

    subcommand = staticmethod(subcommand)
    # Now a static method. Can no longer be called during class definition phase.

这样做有点脆弱,因为一旦你把它改成静态方法,就不能在父类中再使用它了。更稳妥的做法是添加一个中间类:

class Command(object):
    @staticmethod
    def subcommand(method):
        method.is_subcommand = True

        return method

class CommandBase(Command):

    @Command.subcommand
    def common(self):
        print "this subcommand is available to all child classes"

现在你可以让所有的类都继承自 CommandBase,而不是 Command

撰写回答