在类中定义装饰器,这也可以在类定义中使用

Ben*_*ank 5 python class decorator

我正在尝试将一个"子命令"系统实现为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"
Run Code Online (Sandbox Code Playgroud)

我实现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"
Run Code Online (Sandbox Code Playgroud)

到目前为止,我发现的唯一替代方法是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
Run Code Online (Sandbox Code Playgroud)

然而,作为在添加装饰器之前从未使用过Python的人,这对我来说非常笨重.是否有更优雅的方式来实现这一目标?

aar*_*ing 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.
Run Code Online (Sandbox Code Playgroud)

这有点脆弱,因为在将它设为静态方法后,您无法在父类中使用它.更强大的方法是添加一个中间类:

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"
Run Code Online (Sandbox Code Playgroud)

您现在可以继承CommandBase而不是继承所有类Command.