首页
学习
活动
专区
工具
TVP
发布

Python 装饰器详解

代码要遵循开发封闭原则,虽然这个原则是用于面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:

封闭:已实现的功能代码块,已经写好的函数不要更改

开放:对扩展开放,

而这正好可以用装饰器来实现。

Python 装饰器用于修改函数。

装饰器本质上是一个函数,它将被装饰的函数作为参数,然后用其返回的函数来替换那个被装饰的函数

1,最基本的装饰器

>>>defouter(func):

definner():

print("change~"+func())

ret = func()# 1

returnret +"~1"

returninner

>>>deffoo():

return"foo"

>>> foo = outer(foo)#2

change~foo

'foo~1'

# 下面语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约#翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种#语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加#程序的可读性,从而减少程序代码出错的机会。

#只有CPU的微代码不是语法糖,其余代码包括机器语言都是语法糖

>>> @outer

deffoo():

return"foo"

change~foo

'foo~1'

请仔细看这个装饰器示例。首先,定义了一个带单个参数 func 的名为 outer 的函数。然后在 outer 内部定义了一个内嵌函数 inner。inner 函数将打印一行字符 串 ,用来直观的告诉读者这里对要修改的函数进行了修改(change~foo)。并 在 #1 处获取其返回值。在每次 outer 被调用时,func 的值可能都会不同,但不论 func 是什么函数,都将调用它。最后,inner 返回 func() 的返回值加"~ 1"。在 #2 处可以看到,当调用赋值给 foo 的返回函数时,得到的是一行文本输出和返回值 'foo~1',而非期望的调用foo 的返回值 "foo"。

我们可以说等号左边的foo是原foo的装饰版 ,outer将函数foo装修一新了。

2,注册装饰器

_functions= {}

defregister(f):

global_functions

_functions[f.__name__] = f

returnf

@register

deffoo():

return"bar"

在这个例子中,函数被注册并存储在一个字典里,以便后续可以根据函数名字提取函数。

3,被装饰函数带一个固定参数的装饰器

importtime

defdecorator(fun):defwrapper(name):start = time.time()fun(name) runtime = time.time()-start

print(runtime)

returnwrapper

@decorator

defdo_something(name):

foriinrange(1000000):

passprint("play game "+ name)

do_something("san guo sha")

结果如下:

play game san guo sha

0.109375

实现很简单, 就是给wrapper函数加入相同的参数

4,被装饰函数带二个固定参数的装饰器

importtime

defdecorator(fun):

defwrapper(name1,name2):

start = time.time()

fun(name1,name2)

runtime = time.time()-start

print(runtime)

returnwrapper

@decorator

defdo_something(name1,name2):

foriinrange(1000000):

pass

print("play game "+name1+" & "+name2)

do_something("san guo sha","game2")

结果如下:

play game san guo sha & game2

0.109375

5. 目标函数带不固定参数的装饰器

importtime

defdecorator(fun):

defwrapper(*args, **kwargs):

start = time.time()

fun(*args, **kwargs)

runtime = time.time()-start

print(runtime)

returnwrapper

@decorator

defdo_something(name):

foriinrange(1000000):

pass

print("play game "+ name)

@decorator

defdo_something2(user, name):

foriinrange(1000000):

pass

print(user+" play game "+ name)

do_something("san guo sha")

do_something2("wang xiao er","san guo sha")

结果如下:

play game san guo sha

0.109375

wang xiao er play game san guo sha

0.125

6. 让装饰器带参数

importtime

defdecorator(max):

def_decorator(fun):

defwrapper(*args, **kwargs):

start = time.time()

foriinrange(max):

fun(*args, **kwargs)

runtime = time.time()-start

print(runtime)

returnwrapper

return_decorator

@decorator(2)

defdo_something(name):

foriinrange(1000000):

pass

print("play game "+ name)

do_something("san guo sha")

运行结果如下:

play game san guo sha

play game san guo sha

0.25

等同于下面

importtime

defdecorator(max):

def_decorator(fun):

defwrapper(*args, **kwargs):

start = time.time()

foriinrange(max):

fun(*args, **kwargs)

runtime = time.time()-start

print(runtime)

returnwrapper

return_decorator

defdo_something(name):

foriinrange(1000000):

pass

print("play game "+ name)

#@decorator(2)

do_something= decorator(2)(do_something)

do_something("san guo sha")

play game san guo sha

play game san guo sha

0.265625

7. 一个函数可以被多个装饰器装饰

defd1(func):

definner(*args,**kwargs):

# 验证1

returnfunc(*args,**kwargs)

returninner

def(func):

definner(*args,**kwargs):

# 验证1

returnfunc(*args,**kwargs)

returninner

@d1

@d2

deff(arg1,arg2,arg3):

print('f')

f(1,2,3)

运行结果如下:

f

相当于:

defd1(func):

definner(*args,**kwargs):

# 验证1

returnfunc(*args,**kwargs)

returninner

def(func):

definner(*args,**kwargs):

# 验证1

returnfunc(*args,**kwargs)

returninner

deff(arg1,arg2,arg3):

print('f')

f = d1(d2(f))

f(1,2,3)

运行结果如下:

f

另外形式:

@f1(arg)

@f2

deffunc():pass

相当于

deffunc():pass

func = f1(arg)(f2(func))

8. 类也可以装饰:就像装饰函数一样

@f1(arg)

@f2

classFoo:pass

大致相当于

classFoo:pass

Foo = f1(arg)(f2(Foo))

装饰器表达式的计算规则与函数装饰器的计算规则相同。然后将结果绑定到类名。

准确理解—与曾工一块学习

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180307G13R3E00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券