1 引言

装饰器(Decorators)可能是Python中最难掌握的概念之一了,也是最具Pythonic特色的技巧,深入理解并应用装饰器,你会更加感慨——人生苦短,我用Python。

2 初步理解装饰器

2.1 什么是装饰器

在解释什么是装饰器之前,我们有必要回顾一下Python中的一些思想和概念。我们都知道,Python是一门面向对象的语言,Python基本思想就是一些皆对象,数据类型是对象、类是对象、类实例也是对象……对于接下来我们要说的装饰器而言,最重要的是,函数也是对象!

你没看错,函数也和数据类型等概念一样,都是对象,那么既然数据类型可以进行赋值操作,那么函数是不是也可以赋值呢?当然可以!

defdo_something():print('完成一些功能')if __name__ == '__main__':

do=do_something

do()

输出:

完成一些功能

看,原本我们定义的函数名是do_something,但我们把函数赋值给do后,也可以通过do()调用函数。不仅如此,函数当做参数传递给其他函数:

defdo_something():print('正在完成功能')deffunc(f):

f()if __name__ == '__main__':

func(do_something)

输出:

完成一些功能

正是因为Python中函数既可以赋值给其他变量名,也可以当做参数参数进其他函数,所以,上面的代码没有任何问题。

当然,毕竟被称呼为函数,有别有变量之类的概念,所以它也有自己的特性,例如在函数内部,还可以定义函数,甚至作为返回值返回:

deffunc():definner_func():print('我是內部函数')returninner_funcif __name__ == '__main__':

fun1=func()

fun1()

输出结果:

我是內部函数

我们来总结一下函数的这几个特性:

可以赋值给其他变量;

可以作为参数传递给其他函数;

可以在内部定义一个函数;

可以当做返回值返回。

不要疑惑我为什么要着重说明Python中函数的这几个特性,因为装饰器中正是这几个特性为基石。为什么这么说呢?从本质上来说,装饰器就是一个函数,它也具有我们上面说到的4个特性,而且充分利用了这4个特性。装饰器接受一个普通函数作为参数,并在内部定义了一个函数,在这个内部函数中实现了一些功能,并调用了传递进来的函数,最后将内部函数作为返回值返回。如果一个函数把这个步骤全走了一遍,我们就可以认为,这个函数是一个装饰器函数,或者说装饰器。

我们来动手写一个装饰器:

deffunc(f):definner_func():print('{}函数开始运行……'.format(f.__name__))

f()print('{}函数结束运行……'.format(f.__name__))returninner_funcdefdo_something():print('正在完成功能')if __name__ == '__main__':

do_something=func(do_something)

do_something()

输出结果:

do_something函数开始运行……

正在完成功能

do_something函数结束运行……

在上面代码中,我们将do_something方法作为参数传递给func方法,在func方法内部我们定义了一个inner_func方法,并在这个方法中添加了函数开始执行和结束执行的提示,在func方法最后,我们将inner_func作为参数返回,更加值得一说的是,我们重新将func函数的返回值赋给了do_something,所以,最后一行我们再次调用的do_something方法已经不再是最初的do_something函数,而是func方法内定义的inner_func函数,所以最后执行do_something函数时,会有函数开始执行和结束执行的提示功能,而后面再调用do_something函数时,也都直接使用do_something()。

正如你所预料,func函数就是一个装饰器,捋一捋你会发现,func函数把我们上面说过的所有特性、步骤全实现了。

如果你在别处见过Python装饰器的使用,你可能会疑惑,我们实现的func装饰器跟你见过的装饰器不都一样,因为在实际应用中,装饰器大多是与“@”符号结合起来使用。其实“@”符号所实现的功能就是 do_something = func(do_something)这行代码的功能。来,我们尝试一下使用“@”:

deffunc(f):definner_func():print('{}函数开始运行……'.format(f.__name__))

f()print('{}函数结束运行……'.format(f.__name__))returninner_func

@funcdefdo_something():print('正在完成功能')if __name__ == '__main__':

do_something()

输出结果:

do_something函数开始运行……

正在完成功能

do_something函数结束运行……

之前我们知道,func函数就是一个装饰器,所以使用“@”符号时,我们只需要在被装饰的函数前面加上“@func”就表示该函数被func装饰器装饰,在需要处直接调用do_something函数即可。

2.2 为什么要用装饰器

在上面代码中,我们写了一个装饰器func,在这个装饰器中,使用装饰器的好处就已经初见端倪了。

(1)可以在不对被装饰函数做任何修改的前提下,给被装饰函数附加上一些功能。使用@func对do_something函数进行装饰时,我们没有对do_something函数的代码做什么的改变,但是被装饰后的do_something函数却多了开始运行和结束运行的功能。

(2)不改变被装饰函数的调用方式。在被装饰前,我们通过do_something()调用这个函数,被装饰后,还是通过do_something()调用这个函数。

(3)代码更加精简。在上面代码中,我们只是用@func装饰了do_something一个函数,但是如果有多个函数需要添加开始运行和结束运行的提示功能,如果不用装饰器,那么就需要对每一个函数进行修改,则工作量和需要修改的代码量……用了装饰器之后,只需要在需要添加这一功能的函数前面添加@func就可以了。

一言以盖之,装饰器可以在不改变原函数调用方式和代码情况下,为函数添加一些功能,使代码更加精简。

我们在写一个装饰器来加深一下理解。相比大家都写过代码来统计一个函数的运行时间的功能,我们使用装饰器来实现一下这个功能:

importtimedeftimmer(f):definner_func():

start_time=time.time()

f()

end_time=time.time()print('{}函数运行消耗时间为:{}'.format(f.__name__, end_time-start_time))returninner_func

@timmerdefdo_something():print('do_something函数运行……')

time.sleep(1)if __name__ == '__main__':

do_something()

输出结果:

do_something函数运行……

do_something函数运行消耗时间为:1.000662088394165

在上面例子中,我们首先定义了一个计时装饰器timmer,当需要统计某个函数运行时间时,只需要在函数定义时,在前面添加一行写上@timmer即可,例如上面对do_something函数运行时间进行统计,对do_something原来要实现什么功能就继续实现这一功能,原来代码该怎样还怎样,该怎么调用还怎么调用。所以说,使用装饰器可以在不改变原函数代码和调用方式的情况下附加上其他功能。

如果你阅读到了这里,我想你对装饰器已经有了初步的理解。接下来,我们继续聊一聊更加复杂的装饰器。

3 深入理解装饰器

3.1 被装饰的函数带返回值

我们上面写的两个装饰器所装饰的do_something函数是没有返回值的,但大多数函数可都是有返回值的。针对有返回值的函数,装饰器该怎么写呢?

deffunc(f):definner_func():print('{}函数开始运行……'.format(f.__name__))

ret=f()print('{}函数结束运行……'.format(f.__name__))return ret #这里返回值

returninner_func

@funcdefdo_something():print('正在完成功能')return '我是返回值'

if __name__ == '__main__':

ret=do_something()print(ret)

输出结果:

do_something函数开始运行……

正在完成功能

do_something函数结束运行……

我是返回值

我们知道,被装饰后的do_something函数其实不再是最初的do_something函数,而是装饰器内部定义的inner_func函数,所以,被装饰的函数的返回值只需要通过装饰器内部定义的inner_func函数返回返回即可即可。有点绕,不过对着上面的代码应该好理解。

3.2 被装饰函数带参数

对于装饰器,我们要深刻理解一件事:以上面的装饰器func和被装饰函数do_something为例,被装饰后的do_something函数已经不再是原来的do_something函数,而是装饰器内部的inner_func函数。这句话我已经在上文中我已经不止提过一次,因为真的很重要。如果被装饰的函数有参数(加入参数为name),我们还是通过do_something(name)的方式传递传输,不过,既然我们最终调用的时候,通过do_something实质调用的inner_func函数,那么在定义装饰器是,定义的inner_func函数时也需要接受参数。

deffunc(f):definner_func(name):print('{}函数开始运行……'.format(f.__name__))

ret=f(name)print('{}函数结束运行……'.format(f.__name__))returnretreturninner_func

@funcdefdo_something(name):print('你好,{}!'.format(name))return '我是返回值'

if __name__ == '__main__':

ret= do_something('姚明')print(ret)

输出结果:

do_something函数开始运行……

你好,姚明!

do_something函数结束运行……

我是返回值

一个装饰器可用于装饰千千万万个函数,则千千万万个函数参数情况可能各不相同,有的没有参数,有的可能多个参数,甚至还有关键字参数,对于这参数情况不同的函数,我们不可能为每个函数都写一个func装饰器,那怎么办呢?

Python中提供了*args, **kwargs这种机制来接受任意位置的位置参数和关键字参数,参数前面带*表示接受任意个数位置参数,接收到的所有位置参数存储在变量名为args的元组中,带**表示接受任意个数的关键字参数,接收到的所有关键字参数以字典的形式参数在变量名为kwargs的字典中。

当我们知道只有位置参数,但不知道有多少个位置参数是func装饰器可以这么写:

deffunc(f):def inner_func(*name):print('{}函数开始运行……'.format(f.__name__))

ret= f(*name)print('{}函数结束运行……'.format(f.__name__))returnretreturninner_func

@funcdefdo_something(name):print('你好,{}!'.format(name))

@funcdefdo_something_2(name_1, name_2):print('你好,{}!'.format(name_1))print('你好,{}!'.format(name_2))

@funcdef do_something_3(*name):for n inname:print('你好,{}!'.format(n))if __name__ == '__main__':

do_something('姚明')print('-------------------------------')

do_something_2('姚大明', '姚小明')print('-------------------------------')

do_something_3('姚一明', '姚二明', '姚三明', '姚四明')

输出结果:

do_something函数开始运行……

你好,姚明!

do_something函数结束运行……

-------------------------------

do_something_2函数开始运行……

你好,姚大明!

你好,姚小明!

do_something_2函数结束运行……

-------------------------------

do_something_3函数开始运行……

你好,姚一明!

你好,姚二明!

你好,姚三明!

你好,姚四明!

do_something_3函数结束运行……

上面例子定义func装饰器时,我们用*name来接受任意个数的位置参数,可别以为只能用*args,args只是一个变量名,只不过约定俗成,用的多一些,实际开发时你爱取啥名就用啥名,对于这个知识点不再多说,毕竟本篇主角是装饰器。我们继续装饰器内容!

当我们知道只有关键字参数,却不知道参数个数时,可以func装饰器这么写:

deffunc(f):def inner_func(**name):print('{}函数开始运行……'.format(f.__name__))

ret= f(**name)print('{}函数结束运行……'.format(f.__name__))returnretreturninner_func

@funcdef do_something(name='无名氏'):print('你好,{}!'.format(name))

@funcdef do_something_2(name_1='无名氏', name_2='无名氏'):print('你好,{}!'.format(name_1))print('你好,{}!'.format(name_2))

@funcdef do_something_3(**name):for n inname.keys():print('你好,{}!'.format(name[n]))if __name__ == '__main__':

do_something(name='姚明')print('-------------------------------')

do_something_2(name_1='姚大明', name_2='姚小明')print('-------------------------------')

do_something_3(name_1='姚一明', name_2='姚二明', name_3='姚三明', name_4='姚四明')

输出结果:

do_something函数开始运行……

你好,姚明!

do_something函数结束运行……

-------------------------------

do_something_2函数开始运行……

你好,姚大明!

你好,姚小明!

do_something_2函数结束运行……

-------------------------------

do_something_3函数开始运行……

你好,姚一明!

你好,姚二明!

你好,姚三明!

你好,姚四明!

do_something_3函数结束运行……

事实上,大多数情况下,我们对被装饰函数是一无所知的——我们不知道有多少个位置参数、多少个关键字参数,甚至对有没有位置参数、关键字参数都不知道,这时候,我们就只能*args和**kwargs齐上阵了:

deffunc(f):def inner_func(*name1, **name2):print('{}函数开始运行……'.format(f.__name__))

ret= f(*name1, **name2)print('{}函数结束运行……'.format(f.__name__))returnretreturninner_func

@funcdefdo_something(name):print('你好,{}!'.format(name))

@funcdef do_something_2(name_1, name_2='无名氏'):print('你好,{}!'.format(name_1))print('你好,{}!'.format(name_2))

@funcdef do_something_3(*name1, **name2):for n inname1:print('你好,{}!'.format(n))for n inname2.keys():print('你好,{}!'.format(name2[n]))if __name__ == '__main__':

do_something(name='姚明')print('-------------------------------')

do_something_2(name_1='姚大明', name_2='姚小明')print('-------------------------------')

do_something_3('姚一明', '姚二明', '姚三明', name_4='姚四明')

输出结果:

do_something函数开始运行……

你好,姚明!

do_something函数结束运行……

-------------------------------

do_something_2函数开始运行……

你好,姚大明!

你好,姚小明!

do_something_2函数结束运行……

-------------------------------

do_something_3函数开始运行……

你好,姚一明!

你好,姚二明!

你好,姚三明!

你好,姚四明!

do_something_3函数结束运行……

3.3 装饰器本身带参数

我们上面写的装饰器都没有参数,或者说只有一个自带参数,也就是被装饰函数f。其实,装饰器也是可以有其他参数的,这样的装饰器更加灵活。我们通过实例来说明:现在我们要对上面的func装饰器进行改进,需要做到灵活控制装饰器是用中文输出还是用英文输出,代码如下。

def language(lang='中文'): #这里带参数

def func(f): #往里嵌套了一层

def inner_func(*name1, **name2):if lang=='中文':print('{}函数开始运行……'.format(f.__name__))else:print('The function of {} starts runging…'.format(f.__name__))

ret= f(*name1, **name2)if lang=='中文':print('{}函数结束运行……'.format(f.__name__))else:print('The function of {} ends runging…'.format(f.__name__))returnretreturninner_funcreturnfunc

@language('中文')defdo_something(name):print('你好,{}!'.format(name))

@language('English')defdo_something_2(name):print('你好,{}!'.format(name))if __name__ == '__main__':

do_something(name='姚明')print('-------------------------')

do_something_2(name='姚明')

输出如下:

do_something函数开始运行……

你好,姚明!

do_something函数结束运行……

-------------------------

The function of do_something_2 starts runging…

你好,姚明!

The function of do_something_2 ends runging…

可以看到,通过装饰器带参数的方式,我们只需要在定义被装饰函数时,指定装饰器参数,就可以灵活控制每个被装饰函数提示的语言。

当然,必须承认,装饰器带参数后,看起来更加复杂,需要多嵌套一层函数,由最外层的函数接受参数,里层函数才是真正的装饰器。使用装饰器时,会首先运行带参数的最外层函数,返回装饰器,这一步Python会自动帮我们完成。所以,带参数的装饰器甚至可以这么使用:

h = language('中文')

@hdefdo_something(name):print('你好,{}!'.format(name))

3.4 多层装饰器

装饰器也是可以多层嵌套使用的,也就是说,一个函数可以通过是被多个装饰器所装饰,执行顺序是从下到上的优先顺序加载装饰:

#-*- coding: utf-8 -*-

importtimeprint(1)deffunc(f):print(2)def inner_func(*name1, **name2):print('{}函数开始运行……'.format(f.__name__))

f(*name1, **name2)print('{}函数结束运行……'.format(f.__name__))print(3)returninner_funcprint(4)deftimmer(f):print(5)def inner_timmer(*args, **kwargs):print('开始计时……')

start_time=time.time()

f(*args, **kwargs)

end_time=time.time()print('开始结束……')

time_cost= end_time -start_timeprint('{}函数运行时长为:{}秒'.format(f.__name__, time_cost))print(6)returninner_timmerprint(7)

@func

@timmerdefdo_something(name):

time.sleep(1)print('你好,{}!'.format(name))print(8)defdo_something_2(name):

time.sleep(1)print('你好,{}!'.format(name))if __name__ == '__main__':print(9)

do_something(name='姚明')print('-------------------------')

func(timmer(do_something_2))(name='姚明') #执行效果与上面使用了@符号的do_something一样

输出结果:

1

4

7

5

6

2

3

8

9

inner_timmer函数开始运行……

开始计时……

你好,姚明!

开始结束……

do_something函数运行时长为:1.0004358291625977秒

inner_timmer函数结束运行……

-------------------------

5

6

2

3

inner_timmer函数开始运行……

开始计时……

你好,姚明!

开始结束……

do_something_2函数运行时长为:1.000028133392334秒

inner_timmer函数结束运行……

在上面代码中,我们同时用func和timmer两个装饰器来装饰do_something,从运行结果中可以看出,两个装饰器都发挥了作用。同时,为了方便大家理解,我们使用不带@符号的来使用两个装饰器装饰,两者运行结果是一样的,结合代码中的输出标记,我们来分析一下装饰器的执行过程:开始运行后,1->4->7这几个过程我相信大家都是可以理解的,到了位置7后,遇到了@符号标识的装饰器,而且是多层的,两个@装饰器相当于func(timmer(do_something_2)),所以是先执行timmer函数获取返回值作为参数传递给func,所以有了7之后是5->6,timmer函数返回值是inner_timmer函数,这时候就相当于func(inner_timmer),所以程序退出timmer函数后进入func函数,就有了2->3,从func函数返回后,继续向下执行遇到位置8,然后就进入了主函数运行,所以是8->9,此时的函数是被装饰过的,本质已经是func函数返回的inner_func函数了,所以最终在主函数中执行do_something时执行的是inner_func方法,所以先输出了func装饰器的函数开始提示,然后才是timmer装饰器的计时开始提示。

嗯,有点复杂!

3.5 类装饰器

通过上面的介绍,我想你已经知道,@符号是装饰器的一个表示,或者说一个装饰器语法糖,当使用@时,例如@A,这种语法糖会自动将被装饰函数f作为参数传递给A函数,然后将A函数的返回值重新f给f这个变量名,这就是@语法糖帮我们做的事情,概括来说就是f=A(f)()。

我们现在发散一下思维,假设A如果是一个类会怎么样呢?我们知道当A是一个类时,A()表示调用A类的构造函数__init__实例化一个A类对象,那么A(f)就表示将函数f作为参数传递给A类的构造方法__init__来构造一个A类实例对象,如果使用了@符号,那么这种语法机制就还会在A(f)后面加一个括号变成A(f)(),这是什么鬼?执行一个类实例对象?不过话要说回来,如果A(f)()这种结构要是没有问题,能够成功执行,是不是就意味着Python中类也可以成为装饰器了呢?确实如此。我们先看看通过A()()执行一个类实例对象会怎么样:

classA(object):def __init__(self):print('实例化一个A类对象')def __call__(self, *args, **kwargs):print('__call__方法被调用……')if __name__ == '__main__':

A()()

输出结果:

实例化一个A类对象

__call__方法被调用……

看到没,通过A()()执行一个类实例对象时,执行的是A类内部的__call__方法。那么如果用A用作装饰器时,@A返回的就是A类内部定义的__call__方法,相当于函数装饰器func内的inner_func。来,我们感受一下类装饰器:

classA(object):def __init__(self, f):print('实例化一个A类对象……')

self.f=fdef __call__(self, *args, **kwargs):print('{}函数开始运行……'.format(self.f.__name__))

self.f(*args, **kwargs)print('{}函数结束运行……'.format(self.f.__name__))

@Adefdo_something(name):print('你好,{}!'.format(name))if __name__ == '__main__':

do_something('姚明')

输出结果:

实例化一个A类对象……

do_something函数开始运行……

你好,姚明!

do_something函数结束运行……

如果类装饰器带参数呢?这时候,类装饰器的参数也可定是通过@A(t)的形式传递,这时候,因为@语法糖会自动加括号的原因,结构就编程这样A(t)(),A(t)是类实例对象,A(t)()就是__call__方法,所以,@语法糖会把被装饰函数f作为参数传递给__call__方法,被装饰函数的参数需要在__call__内部定义一个函数来接受。也就是话说,定义类装饰器时,装饰器的参数通过__init__构造方法接收,被装饰函数的作为参数被__call__方法接收,。(这段子很绕,有点烧脑,没点儿Python基础还真不好理解,语言表达能力优先感觉要枯竭了)

importtimeclassA(object):def __init__(self, t):print('实例化一个A类对象……')

self.t=tdef __call__(self, f):def inner_A(*args, **kwargs):print('延迟{}秒后开始执行……'.format(self.t))

time.sleep(self.t)print('{}函数开始运行……'.format(f.__name__))

f(*args, **kwargs)print('{}函数结束运行……'.format(f.__name__))returninner_A

@A(1)defdo_something(name):print('你好,{}!'.format(name))if __name__ == '__main__':

do_something('姚明')

输出结果:

实例化一个A类对象……

延迟1秒后开始执行……

do_something函数开始运行……

你好,姚明!

do_something函数结束运行……

无论是函数装饰器还是类装饰器,原理上是一样的,区别在于如果A是函数,A()是直接调用函数,而A是类时,A()是实例化,通过A()()是调用A类的__call__方法。

4 Python中内置的装饰器

4.1 @property,@setter,@deleter

@property,@setter,@deleter这三个装饰器提供了更加友好的方式来获取、设置或删除类中的属性。@property装饰器所装饰的函数可以像访问属性一样调用函数,注意,@property装饰器必须先于@setter,@deleter使用,且三者说装饰的函数必须同名。

classA(object):def __init__(self, v):print('实例化一个A类对象……')

self.__value =v

@propertydefvalue(self):print('取值时被调用')return self.__value@value.setterdefvalue(self, value):print('赋值时被调用')

self.__value =value

@value.deleterdefvalue(self):print('删除值时被调用……')del self.__value

if __name__ == '__main__':

a= A(123)print('-------------')print('__value的值为:{}'.format(a.value))print('-------------')

a.value= 234

print('__value的值为:{}'.format(a.value))print('--------------')dela.valueprint('__value的值为:{}'.format(a.value))

输出为:

Traceback (most recent call last):

实例化一个A类对象……

-------------

取值时被调用

File "E:/WorkProjectCode/study_pymysql/study_secorators/test2.py", line 33, in

__value的值为:123

-------------

print('__value的值为:{}'.format(a.value))

赋值时被调用

取值时被调用

__value的值为:234

File "E:/WorkProjectCode/study_pymysql/study_secorators/test2.py", line 11, in value

--------------

return self.__value

删除值时被调用……

取值时被调用

AttributeError: 'A' object has no attribute '_A__value'

运行产生异常,因为最后访问了已经删除了的元素。

4.2 @classmethod

在一个类中,如果一个方法被@classmethod所装饰,就代表该方法与类绑定,而不是与实例对象绑定,第一个参数cls由Python机制自动传递,表示类本身。

classA(object):

@classmethoddeff(cls):print('当前类名为:{}'.format(cls.__name__))if __name__ == '__main__':

A.f()

输出结果:

当前类名为:A

4.3 @staticmethod

被@staticmethod所装饰的方法为静态方法,静态方法一般使用场景就是和类相关的操作,但是又不会依赖和改变类、实例的状态,比如一些工具方法。

importtimeclassA(object):

@staticmethoddeff():

time_now= time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))returntime_nowif __name__ == '__main__':print(A.f())print(A().f())

输出:

2019-08-16 19:29:32

2019-08-16 19:29:32

python装饰器原理-Python装饰器完全解读相关推荐

  1. python装饰器原理-Python装饰器原理与用法分析

    这篇文章主要介绍了Python装饰器原理与用法,结合实例形式分析了Python装饰器的概念.原理.使用方法及相关操作注意事项,需要的朋友可以参考下 本文实例讲述了Python装饰器原理与用法.分享给大 ...

  2. python装饰器原理-python 中的装饰器及其原理

    装饰器模式 此前的文章中我们介绍过装饰器模式: 装饰器模式中具体的 Decorator 实现类通过将对组建的请求转发给被装饰的对象,并在转发前后执行一些额外的动作来修改原有的部分行为,实现增强 Com ...

  3. python装饰器原理-python装饰器的原理和使用

    一.最简单的装饰器 装饰器是python中很基础也很实用的一个特性.通过装饰器我们可以很方便地为一些函数添加相同的功能.我们以测量函数运行时间为例来讲一讲python装饰器的运行原理. 1.使用装饰器 ...

  4. python装饰器原理-Python函数装饰器原理与用法详解

    本文实例讲述了Python函数装饰器原理与用法.分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值 ...

  5. python装饰器原理-python装饰器原理与用法深入详解

    本文实例讲述了python装饰器原理与用法.分享给大家供大家参考,具体如下: 你会Python嘛? 我会! 那你给我讲下Python装饰器吧! Python装饰器啊?我没用过哎 以上是我一个哥们面试时 ...

  6. python装饰器原理-Python装饰器原理

    装饰器(Decorator)是面向对象设计模式的一种,这种模式的核心思想是在不改变原来核心业务逻辑代码的情况下,对函数或类对象进行额外的修饰.python中的装饰器由python解释器直接支持,其定义 ...

  7. 调试器原理_调试器的工作原理

    调试器原理 调试器是大多数(如果不是每种)开发人员在软件工程生涯中至少使用一次的软件之一,但是你们当中有多少人知道它们的实际工作原理? 在悉尼举行的linux.conf.au 2018上的演讲中,我将 ...

  8. python装饰器原理-Python装饰器的实现原理

    Python中的装饰器是通过利用了函数特性的闭包实现的,所以在说装饰器之前,我们需要先了解函数特性,以及闭包是怎么利用了函数特性的. 1.函数特性 Python中的函数特性总的来说有四点: 1.函数作 ...

  9. python装饰器原理-Python 装饰器工作原理解析

    #!/usr/bin/env python #coding:utf-8 """ 装饰器实例拆解 """ def login00(func): ...

最新文章

  1. websocket客户端
  2. 常见的冒泡排序、顺序查找和对半查找
  3. 一个关于小程序Iot的具体实现(MQTT版)
  4. Mapped Statements collection does not contain value for 之运行异常原因
  5. 录音降噪哪家强?搜狗西工大联合团队DNS挑战赛夺冠
  6. Exchange-OWA与域控集成-实现单点登录
  7. VS2013+OpenCV3.4.2编译
  8. linux下安装c/c++环境(gcc/gcc+)
  9. 【做题记录】CF1444A Division
  10. 水晶报表-控制结构-For 循环(Crystal 语法)
  11. 【Java从0到架构师】Maven - 依赖冲突、分模块构建项目
  12. 学生选课系统 c语言
  13. mongodb java报授权,MongoDB认证和授权
  14. Python 简单的爬虫爬取网页框架(爬取网页框架+实例)
  15. 十几减9的口算题_十几减9精品口算练习
  16. PAT甲之初窥门径(上)
  17. 拼多多开店怎么做推广?四川万顿思
  18. qcow2文件的snapshot管理
  19. 2022年危险化学品经营单位主要负责人特种作业证考试题库及答案
  20. 数据链路层---差错检测和纠正

热门文章

  1. oracle 性能优化--索引总结
  2. iOS基础-高级视图-UITableView--实例:app管理
  3. 2011年7个最佳的Linux发行版
  4. C#与.NET程序员面试宝典 1.4.3 笔试(举例微软、雅虎笔试题目)
  5. 2017年06月07号课堂笔记
  6. Android可视化界面开发工具DroidDraw
  7. 用ruby的net/ssh链接远程的服务器
  8. php恶意代码,警惕WordPress主题functions.php包含的恶意代码
  9. python程序设计 清华大学出版社 pdf下载-清华大学出版社-图书详情-《Python 程序设计》...
  10. python是动态编程语言吗-python是一种跨平台、开源、免费的高级动态编程语言,对么...