2016-01-22 52 views
2

我試圖在函數send上設置超時。使用裝飾器超時類中的函數

我已經找到了一些要素,這些帖子:

第一個似乎適用於所有的功能,而不是一個精確的一個,這就是爲什麼我選擇了像第二個一樣的裝飾器實現。

我試圖混合起來,我有這樣的:

from functools import wraps 
import os 
import signal 

class TimeoutError(Exception): 
    pass 

def timeout_func(error_message="Timeout in send pipe!"): 
    def decorator(func): 
     def _handle_timeout(signum, frame): 
      if args[0].action=="warn": 
       print "WARNING : ",error_message 
      elif args[0].action=="kill": 
       raise TimeoutError(error_message) 

     def wrapper(*args, **kwargs): 
      print args 
      signal.signal(signal.SIGALRM, _handle_timeout,args[0].action) 
      signal.alarm(args[0].seconds) 
      print str(args) 
      try: 
       result = func(*args, **kwargs) 
      finally: 
       signal.alarm(0) 
      return result 
     return wraps(func)(wrapper) 
    return decorator 

class Link(object): 
    def __init__(self,timeout=1,action="warn"): 
     self.timeout=timeout 
     self.action=action 

    @timeout_func 
    def send(self,value): 
     print "working : ", value 

它給了我這樣的:

In [6]: l=Link()

In [7]: l.send(1) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in() ----> 1 l.send(1)

TypeError: decorator() takes exactly 1 argument (2 given)

我的問題是,我想的超時值second傳遞給裝飾通過Linkself。我不完全理解這裏的整個裝飾器機制,也不能弄清楚什麼是錯的。

有人可以解釋我這個裝飾器是如何工作的,我應該修改什麼來修復它?或者如果你想到一個更簡單/更明確的解決方案來實現它?

回答

0

所以我一直在調試我的問題,我找到了工作液:

from functools import wraps 
import signal 

class TimeoutError(Exception): 
    pass 

def timeout_func(f): 
    def _handle_timeout(signum, frame): 
     raise TimeoutError("timeout error") 

    def wrapper(*args): 
     signal.signal(signal.SIGALRM, _handle_timeout) 
     signal.setitimer(signal.ITIMER_REAL,args[0].timeout) #args[0] is self of Link class here 
     try: 
      result = f(*args,**kwargs) 
     finally: 
      signal.alarm(0) 
     return result 
    return wrapper 


class Link(object): 
    def __init__(self,timeout=0.1,action="warn"): 
     self.timeout=timeout 
     self.action=action 

    def send(self,value): # I use this func to handle the exceptions 
     try: 
      self.send_timeout(value) # call the timeout function 
     except TimeoutError as e: # handle Timeout exception 
      if self.action=="warn": 
       print "WARNING : Timeout error in pipe send!" 
      elif self.action=="kill": 
       print "Killing Link : ", e 
       raise 
     except (Exception,KeyboardInterrupt) as e: 
      print "Exception in link : ", e 
      raise 

    @timeout_funC# apply timeout decorator to this function 
    def send_timeout(self,value): 
     # DO STUFF HERE 

要叫它:

l=Link() 
l.send("any value") 

我用signal.setitimer(signal.ITIMER_REAL,args[0].timeout),因爲它允許設置超時<1秒,與signal.signal()不一樣,只接受整數作爲定時器。