10

いくつかの基本クラスがあるとしましょう:

class Task:
    def run(self):
        #override this!

ここで、他のユーザーに Task をサブクラス化し、run() メソッドをオーバーライドしてもらいたい:

class MyTask(Task):
    def run(self):
        #successful override!

ただし、問題は、Task をサブクラス化するすべてのクラスの run() メソッドの前後に実行する必要があるロジックがあることです。

これを行う方法の 1 つは、基本クラスで別のメソッドを定義してから run() メソッドを呼び出すことです。しかし、デコレータでこれを達成する方法はありますか? これを行うための最もpythonicな方法は何でしょうか?

4

1 に答える 1

17

コメントで示唆されているように、サブクラスがrunそれ自体ではなくフックをオーバーライドできるようにするのがおそらく最善です。

class Task(object):
    def run(self):
        # before 
        self.do_run()
        # after

class MyTask(Task):
    def do_run(self):
        ...

task = MyTask()
task.run()

ただし、これはクラス デコレータを使用して実行できる1 つの方法です。

def decorate_run(cls):
    run = getattr(cls, 'run')
    def new_run(self):
        print('before')
        run(self)
        print('after')
    setattr(cls, 'run', new_run)
    return cls


class Task(object): pass

@decorate_run
class MyTask(Task):
    def run(self):
        pass

task = MyTask()
task.run()

# prints:
# before
# after

別の方法は、メタクラスを使用することです。メタクラスを使用する利点は、サブクラスを装飾する必要がないことです。Taskメタクラスのインスタンスにすることができ、その後、すべてのサブクラスがTaskメタクラスを自動的に継承します。

class MetaTask(type):
    def __init__(cls, name, bases, clsdict):
        if 'run' in clsdict:
            def new_run(self):
                print('before')
                clsdict['run'](self)
                print('after')
            setattr(cls, 'run', new_run)

class Task(object, metaclass=MetaTask):
    # For Python2: remove metaclass=MetaTask above and uncomment below:
    # __metaclass__ = MetaTask
    pass

class MyTask(Task):
    def run(self):
        #successful override!
        pass

task = MyTask()
task.run()
于 2013-09-17T20:09:44.967 に答える