下面是小编整理的python使用装饰器和线程限制函数执行时间的方法(共含9篇),欢迎您阅读,希望对您有所帮助。同时,但愿您也能像本文投稿人“随便看看吧”一样,积极向本站投稿分享好文章。
作者:lele 字体:[增加 减小] 类型:
这篇文章主要介绍了python使用装饰器和线程限制函数执行时间的方法,主要涉及timelimited函数的使用技巧,非常具有实用价值,需要的朋友可以参考下
本文实例讲述了python使用装饰器和线程限制函数执行时间的方法,分享给大家供大家参考。具体分析如下:
很多时候函数内部包含了一些不可预知的事情,比如调用其它软件,从网络抓取信息,可能某个函数会卡在某个地方不动态,这段代码可以用来限制函数的执行时间,只需要在函数的上方添加一个装饰器,timelimited(2)就可以限定函数必须在2秒内执行完成,如果执行完成则返回函数正常的返回值,如果执行超时则会抛出错误信息。
# -*- coding: utf-8 -*-from threading import Threadimport timeclass TimeoutException(Exception): passThreadStop = Thread._Thread__stop#获取私有函数def timelimited(timeout): def decorator(function): def decorator2(*args,**kwargs):class TimeLimited(Thread): def __init__(self,_error= None,): Thread.__init__(self) self._error = _error def run(self): try:self.result = function(*args,**kwargs) except Exception,e:self._error =e def _stop(self): if self.isAlive:ThreadStop(self)t = TimeLimited()t.start()t.join(timeout)if isinstance(t._error,TimeoutException): t._stop() raise TimeoutException(‘timeout for %s‘ % (repr(function)))if t.isAlive(): t._stop() raise TimeoutException(‘timeout for %s‘ % (repr(function)))if t._error is None: return t.result return decorator2 return decorator@timelimited(2)def fn_1(secs): time.sleep(secs) return ‘Finished‘if __name__ == “__main__”: print fn_1(4)
希望本文所述对大家的Python程序设计有所帮助,
Python中的装饰器的概念经常会让人搞得一头雾水,所以今天就好好来分析一下python中的装饰器.
先看一个简单的装饰器用法:
复制代码
1 def decorator(func):
2 print(“this is wrapper”)
3
4 def wrapper():
5 func()
6
7 return wrapper
8
9
10 @decorator
11 def func():
12 print('this is func')
13
14 # func()
15 # print(func.__name__)
复制代码
运行一下上述代码,看看输出.再把14,15行的注释放开,看看输出.
我们发现当14,15行注释掉时,输出this is wrapper,
15行注释放开,你会发现先func()的名字变成了wrapper。
@其实就是python中的一个语法糖.装饰器的本质以上述代码为例:
@decorator
def func():
print('this is func')
其实解释器执行了这么一句:func = decorator(func).这就是装饰器最本质最核心的东西了.
func作为参数传递给decorator,decorator的返回值是wrapper(),赋给func.就这样被修饰的函数func其实已经变成了另一个函数wrapper了.
下面我们就来看看几个例子:
1.你想写这样一个装饰器:
@decorator
def func(user):
print(“this”,user,“ func”)
要怎么写呢?
我们来看看func = decorator(func).
第一步:我们知道decorator(func)应该返回一个函数.所以有如下代码.
def decorator(func):
def wrapper():
pass
return wrapper
第二步:装饰器是用来装饰函数的,你不能把原有的要装饰的func(user)的功能给弄没了啊.所以我们补全wrapper()
def decorator(func):
def wrapper(user):
print(“start decorate”,user)
func(user)
return wrapper
这时候你要装饰的func(user)就变成wrapper(user)啦.
完整代码:
2.一个装饰器想装饰好几个函数.
比如:
复制代码
@decorator
def func(user):
print(user)
@decorator
def func2(user1,user2):
print(user1,“and”,user2)
复制代码
要装饰的函数的参数你不确定有几个.可以用*args,**args表示任意参数就可以了.
复制代码
def decorator(func):
def wrapper(*args,**kwargs):
print(“start decorate”)
func(*args)
return wrapper
@decorator
def func(user):
print(user)
@decorator
def func2(user1,user2):
print(user1,“and”,user2)
func('tim')
func2('joe','jimmy')
复制代码
3.多个装饰器修饰一个函数
@decorator0
@decorator1
def func():
print(“this is func”)
实际上解释器执行func = decorator0(decorator1(func))
可以分两步:
1.decorator1(func)返回一个函数
2.decorator0()接受一个函数作为参数,并返回一函数.
所以就有了:
def decorator1(func):
def wrapper():
print(“decorator1!”)
func()
return wrapper
def decorator0(func):
def wrapper():
print(“decorator0!”)
func()
return wrapper
完整代码
复制代码
#func = decorator0(decorator1(func))
def decorator0(func):
def wrapper():
print(“decorator0!”)
func()
return wrapper
def decorator1(func):
def wrapper():
print(“decorator1!”)
func()
return wrapper
@decorator0
@decorator1
def func():
print(“this is func”)
print(func.__name__)
func()
复制代码
4.装饰器带参数
@decorator(num)
def func(user):
print(user)
实际上解释器执行func = decorator(num)(func)
也就是说你可以认为1.decorator(num)返回一个函数.2.返回的函数的类型是:以func为参数,返回值是一个函数.
所以第一步:
def decorator(num):
def wrapper():
pass
return wrapper
第二步:
复制代码
def decorator(num):
def wrapper(func):
def wrapper2(user):
print(num)
func(user)
return wrapper2
return wrapper
由于函数也是一个对象,而且函数作为一个特殊的对象可以被赋值给其他变量(value = pringname),相反,通过变量也是可以调用函数的,以下是一个简单的例子:
1 >>>def printName():
2 ... print(“My name is Jobs”)
3 ...
4 >>>name = printName
5 >>>
6 >>>printName()
7 My name is Jobs
8 >>>name()
9 My name is Jobs
由以上代码我们不难看出,printName()函数被赋值给name变量,同样用name变量也可以调用printName()函数,此时他们是相同的,在这里说一点小知识:函数对象有
一个__name__属性,可以拿到函数的名字:
例子:
1 >>>
2 >>>name.__name__
3 'printName'
4 >>>printName.__name__
5 'printName'
6
7
现在,假设我们要增强printName函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改printName函数的定义,这种在代码运行期间动态增加功能的方式,称之为“
装饰器”(Decorator)。本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:
例子一:
1 >>>
2 >>>def log(func):
3 ... def wrapper(*args,**kw):
4 ... print 'call %s()' %func.__name__
5 ... return func(*args,**kw)
6 ... return wrapper
7 ...
观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:
1 >>>@log
2 ... def printName():
3 ... print(“My name is Jobs”)
4 ...
5 >>>printName()
6 call printName()
7 My name is Jobs
例子二:
1 >>>
2 >>>@log
3 ... def printAge():
4 ... print '%s,my age is 120' %printName()
5 ...
6 >>>job = printAge()
7 call printAge()
8 call printName()
9 My name is Jobs
10 None,my age is 120
当你调用printName或者printAge()时,不仅会调用函数本身,而且会调用在调用该函数之前打印一些日志。把@log放在printAge()函数之前相当于执行了语句:
name= log(printName)
由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的printName()了新的函数,于是调用printName()将执行新函数,即在log()函数中返回的wrapper()函数。
wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:
1 def log(text):
2 def decorator(func):
3 def wrapper(*args, **kw):
4 print '%s %s():' % (text, func.__name__)
5 return func(*args, **kw)
6 return wrapper
7 return decorator
这个3层嵌套
1 >>>def log(text):
2 ... def decorator(func):
3 ... def wrapper(*args,**kw):
4 ... print '%s %s():' %(text,func.__name__)
5 ... return func(*args,**kw)
6 ... return wrapper
7 ... return decorator
8 ...
9 >>>@log('excute')
10 ... def printName():
11 ... print(“My name is Jobs!”)
12 ...
13 >>>printName()
14 excute printName():
15 My name is Jobs!
16 >>>
我们来剖析上面的语句,首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数,
以上两种decorator的定义都没有问题,但还差最后一步。因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的'printName变成了'wrapper':
>>>printName.__name__
'wrapper'
>>>
因为返回的那个wrapper()函数名字就是'wrapper',所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。
不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:
1 >>>def log(func):
2 ... @functools.wraps(func)
3 ... def wrapper(*args,**kw):
4 ... print 'call %s():' %func.__name__
5 ... return func(*args,**kw)
6 ... return wrapper
7 ...
8 >>>
也可以针对呆参数的decorator:
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return wrapper
return decorator
这是一个更新的例子,希望帮助大家理解:
1 >>>def deco(func):
2 ... def _deco(a,b):
3 ... print (“before myfunc() called.”)
4 ... ret = func(a,b)
5 ... print(“after called.result:%s” %ret)
6 ... return ret
7 ... return _deco
8 ...
9
10 >>>@deco
11 ... def myfunc(a,b):
12 ... print(“myfunc(%s,%s) called.”%(a,b))
13 ... return a+b
14 ...
15 >>>myfunc(1,2)
16 before myfunc() called.
17 myfunc(1,2) called.
18 after called.result:3
19 3
20 >>>
补充说明:
其实,装饰器就是一个函数,一个可以用来包装函数的函数,最后返回一个修改之后的函数(这里的修改,比如增加日志,如上例。)将其重新赋值原来的标识符,并永久丧失对原始函数对象的访问。
大家都知道装饰器是一个很著名的设计模式,经常被用于AOP(面向切面编程)的场景,较为经典的有插入日志,性能测试,事务处理,Web权限校验
,Cache
等,
Python语言本身提供了装饰器语法(@),典型的装饰器实现如下:
@function_wrapper def function(): pass
@实际上是python2.4才提出的语法糖,针对python2.4以前的版本有另一种等价的实现:
def function(): pass function = function_wrapper(function)
函数包装器 - 经典实现
def function_wrapper(wrapped): def _wrapper(*args, **kwargs):return wrapped(*args, **kwargs) return _wrapper @function_wrapper def function: pass
类包装器 - 易于理解
class function_wrapper(object): def __init__(self, wrapped):self.wrapped = wrapped def __call__(self, *args, **kwargs):return self.wrapped(*args, **kwargs) @function_wrapper def function(): pass
当我们谈到一个函数时,通常希望这个函数的属性像其文档上描述的那样,是被明确定义的,例如__name__
和__doc__
。
针对某个函数应用装饰器时,这个函数的属性就会发生变化,但这并不是我们所期望的。
def function_wrapper(wrapped): def _wrapper(*args, **kwargs):return wrapped(*args, **kwargs) return _wrapper @function_wrapper def function(): pass >>>print(function.__name__) _wrapper
python标准库提供了functools.wraps()
,来解决这个问题。
import functools def function_wrapper(wrapped): @functools.wraps(wrapped) def _wrapper(*args, **kwargs):return wrapped(*args, **kwargs) return _wrapper @function_wrapper def function(): pass >>>print(function.__name__) function
然而,当我们想要获取被包装函数的参数(argument
)或源代码(source code
)时,同样不能得到我们想要的结果。
import inspect def function_wrapper(wrapped): ... @function_wrapper def function(arg1, arg2): pass >>>print(inspect.getargspec(function)) ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None) >>>print(inspect.getsource(function)) @functools.wraps(wrapped) def _wrapper(*args, **kwargs):return wrapped(*args, **kwargs)
尽管大家实现装饰器所用的方法通常都很简单,但这并不意味着它们一定是正确的并且始终能正常工作。
如同上面我们所看到的,functools.wraps
可以帮我们解决__name__
和__doc__
的问题,但对于获取函数的参数(argument)或源代码(source code
)则束手无策。
本文系OneAPM工程师编译整理。OneAPM是中国基础软件领域的新兴领军企业,能帮助企业用户和开发者轻松实现:缓慢的程序代码和SQL语句的实时抓取。想阅读更多技术文章,请访问OneAPM官方技术博客。
当包装器(@function_wrapper
)被应用于@classmethod
时,将会抛出如下异常:
class Class(object): @function_wrapper @classmethod def cmethod(cls):pass Traceback (most recent call last):File “
因为@classmethod
在实现时,缺少functools.update_wrapper
需要的某些属性,
这是functools.update_wrapper
在python2中的bug,3.2版本已被修复,参考bugs.python.org/issue3445。
然而,在python3下执行,另一个问题出现了:
class Class(object): @function_wrapper @classmethod def cmethod(cls):pass >>>Class.cmethod() Traceback (most recent call last):File “classmethod.py”, line 15, in
这是因为包装器认定被包装的函数(@classmethod
)是可以直接被调用的,但事实并不一定是这样的。被包装的函数实际上可能是描述符(descriptor
),意味着为了使其可调用,该函数(描述符)必须被正确地绑定到某个实例上。关于描述符的定义,可以参考docs.python.org/2/howto/descriptor.html。
作者:liujian0616 字体:[增加 减小] 类型:转载
这篇文章主要介绍了python实现线程池的方法,实例分析了Python线程池的原理与相关实现技巧,需要的朋友可以参考下
本文实例讲述了python实现线程池的方法,分享给大家供大家参考。具体如下:
原理:建立一个任务队列,然多个线程都从这个任务队列中取出任务然后执行,当然任务队列要加锁,详细请看代码
文件名:thrd_pool.py 系统环境:ubuntu linux & python2.6
import threadingimport timeimport signalimport osclass task_info(object): def __init__(self): self.func = None self.parm0 = None self.parm1 = None self.parm2 = Noneclass task_list(object): def __init__(self): self.tl = [] self.mutex = threading.Lock() self.sem = threading.Semaphore(0) def append(self, ti): self.mutex.acquire() self.tl.append(ti) self.mutex.release() self.sem.release() def fetch(self): self.sem.acquire() self.mutex.acquire() ti = self.tl.pop(0) self.mutex.release() return ticlass thrd(threading.Thread): def __init__(self, tl): threading.Thread.__init__(self) self.tl = tl def run(self): while True:tsk = self.tl.fetch()tsk.func(tsk.parm0, tsk.parm1, tsk.parm2) class thrd_pool(object): def __init__(self, thd_count, tl): self.thds = [] for i in range(thd_count):self.thds.append(thrd(tl)) def run(self): for thd in self.thds:thd.start()def func(parm0=None, parm1=None, parm2=None): print ‘count:%s, thrd_name:%s‘%(str(parm0), threading.currentThread().getName())def cleanup(signo, stkframe): print (‘Oops! Got signal %s‘, signo) os._exit(0)if __name__ == ‘__main__‘: signal.signal(signal.SIGINT, cleanup) signal.signal(signal.SIGQUIT, cleanup) signal.signal(signal.SIGTERM, cleanup) tl = task_list() tp = thrd_pool(6, tl) tp.run() count = 0 while True: ti = task_info() ti.parm0 = count ti.func = func tl.append(ti) count += 1 time.sleep(2) pass
执行方式:python thrd_pool.py
执行结果:
count:0, thrd_name:Thread-1count:1, thrd_name:Thread-2count:2, thrd_name:Thread-3count:3, thrd_name:Thread-4count:4, thrd_name:Thread-5count:5, thrd_name:Thread-1count:6, thrd_name:Thread-6count:7, thrd_name:Thread-2count:8, thrd_name:Thread-3count:9, thrd_name:Thread-4count:10, thrd_name:Thread-5count:11, thrd_name:Thread-1count:12, thrd_name:Thread-6count:13, thrd_name:Thread-2count:14, thrd_name:Thread-3(‘Oops! Got signal %s‘, 15)
希望本文所述对大家的Python程序设计有所帮助,