0

または、私がやろうとしていることの代替ソリューションを考えることができるかもしれません. 基本的に、各関数をきちんとクリーンアップする関数があるため、 KeyboardInterruptエラーをインターセプトするために try/except ブロックでラップしたい関数の束を持つクラスがあります。

各関数に巨大な try catch ブロックを配置する代わりに、それを行うデコレータを作成できると考えましたが、いくつかの問題が発生しています。これまでのところ、私はこのようなものを持っています

class MyClass:
    def catch_interrupt(self, func):
        def catcher():
            try:
                func()
            except KeyboardInterrupt:
                self.End()
        return catcher

    @catch_interrupt
    def my_func(self):
        # Start a long process that might need to be interrupted

    def End(self):
        # Cleans up things
        sys.exit()

これを実行したときの問題は、エラーが発生することです

TypeError: catch_interrupt() takes exactly 2 arguments (1 given)

これは可能ですか?より良い方法はありますか、それとも実際に各関数の内部に try/except ブロックを配置する必要がありますか?

4

2 に答える 2

2

クラス内にデコレータを作成することは確かに可能ですが、実装に問題があります:

まずcatch_interrupt()取れませんself

@catch_interrupt
def my_func(self):
    # Start a long process that might need to be interrupted

と同等です

def my_func(self):
    # Start a long process that might need to be interrupted
my_func = catch_interrupt(my_func)

明らかにこれは許可しませんself

次に、デコレータから返す内部ラッパー関数は、少なくとも をself引数として取り、それを に渡す必要があります。これは、装飾する関数が最初の引数としてfunc期待されるためです。self

また、内部デコレータを呼び出して_catch_interrupt、それが内部で使用するためのものであることを示唆することもできます。それは誰もそれを呼び出すことを妨げませんが、クラスのインスタンスで呼び出された場合の動作が正しくないことを考えると、良い習慣です (たとえば、おそらく望ましくないインスタンス自体MyClass().catch_interrupt()を装飾しようとします)。MyClass


ただし、代わりにコンテキストマネージャーを実装し、クリーンアップを実行することをお勧めします。ステートメントのグループを囲んでいるだけの場合は、よりPythonicであり、正しく実装すれば、実際にデコレーターとしても使用できます。

于 2015-10-14T18:10:12.980 に答える