0

或者你也可以考慮一下我想要做的替代解決方案。基本上我有一堆功能,我想包裝在嘗試/除了塊攔截KeyboardInterrupt錯誤,因爲我有一個函數,整潔地清理了我的每個功能。是否可以在類中創建裝飾器?

而不是把巨大的嘗試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塊?

回答

2

它確實有可能創建一個類內部的裝飾,但你的實現是錯誤的:

首先,catch_interrupt()不能採取self

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

顯然,這並不讓self相當於

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

。其次,從裝飾器返回的內部包裝器函數至少需要採用self作爲參數,並將其傳遞到func,因爲將要裝飾的函數預計將會使用self作爲它們的第一個參數。

您可能還想調用您的內部裝飾器_catch_interrupt以提示它是用於內部使用。這不會阻止任何人調用它,但是如果在類的實例上調用該行爲將會不正確(例如,MyClass().catch_interrupt()將試圖修飾MyClass實例本身,您可能不想這麼做),這是很好的做法。


我的建議,但是,這是實現context manager代替,並讓它執行您的清理。對於只是附上一組語句的情況,Pythonic更具有Pythonic特性,如果您正確實施它,您實際上也可以將其用作裝飾器。

+0

不傳入自我,我會怎樣稱呼我的End()函數? –

+0

@ProgrammerUnextraordinair實現上下文管理器中的行爲,相反,他們有一個自動清理的方法,當上下文保持不變,它甚至需要參數指示退出是由於成功完成還是引發異常。 – JAB

+1

或者,如果您只想堅持使用當前的裝飾器,那麼'catcher()'需要將'self'作爲其第一個參數意味着您仍然可以訪問它。 – JAB

0

我不確定你是否可以在你建議的自然類中使用裝飾器。我認爲這對於裝飾者本身的目的是不直觀的(一個黑客,可以這麼說)。

try-except塊有什麼問題?你已經把所有的清理代碼放在一個函數中,所以都遵守DRY原則。裝飾器和/或包裝器只會限制你的錯誤處理的靈活性,通過修改try-except語句來包裝你的整個函數,而不提供任何真正的附加好處。

相關問題