python之装饰器最全讲解

    不懂指针就不能说自己懂C,那么不懂装饰器,就不能说自己会python。上篇文章说过闭包是用来实现装饰器的,算是有了一个铺垫。

   装饰器从字面意思来理解的话,就是我们对一件事物的装饰。那么我们什么时候选择去装饰一件事物呢?当然是这件事物本身无法满足我们的审美,我们要用一些添加一些装饰器来满足我们的需求。那么结合软件开发的场景。我们有的时候写完一个类,一个方法或者函数,忽然发现功能得不到满足。按照软件开发的开放封闭原则,最好原则上不要修改我们已经写过的代码,因为这毕竟不是重构,怎么办?这时候装饰器就起作用了,装饰器的作用就是为它所装饰的方法添加一些新的功能。所以说,装饰器这个翻译恰到好处,见名知意。装饰器本身对我们来说有巨大的用处,下面结合代码进行讲解。

def set_func(func):
    def call_func():
        print("这是权限验证1")
        print("这是权限验证2")
        func()
    return call_func

@set_func
def test1():
    print("----test1----")

test1()

  运行结果:

  是否感到很神奇?接下来一步一步来分析。首先set_func结合上篇文章可以看出是一个闭包,那么返回的是什么呢?记得上篇文章说过如果是函数名不加括号,相当于返回了函数本身,函数本身是一个变量也是一个对象也是对该函数本身的引用。接着看,到最后test1()函数调用的时候竟然,真的把装饰器里面要加的东西打印出来了,那么此时此刻我有一个大胆的想法,我们是否可以手动的实现装饰器呢?答案是肯定的,下面上代码:

def set_func(func):
    def call_func(num2):
        print("这是权限验证1")
        print("这是权限验证2")
        func(num2)
    return call_func

def test1(num):
    print("----test1----%d"%num)
test1 = set_func(test1)

test1(100)

  运行结果:

哇 真的实现了!下面讲解。test1= set_func(test1)执行之后,我问一个问题,最后test1是包含了谁的引用?答案是test1。首先,set_func返回了call_func的引用。然后,注意一个细节,我们把test1函数本身也传递了进去,所以,当执行test1(100)这个操作的时候,实际上先调用了call_func函数,打印结束后,调用了func函数,但是此时我们知道,由于闭包的特性,func此时调用的就是test1本身,所以最后的打印结果和我们加了装饰器的效果一模一样,这就是装饰器的手动实现。所以我们下次再看见装饰器的时候,就可以认为他执行了以上操作。、

    那么下一个 当装饰器修饰多参数的环境时呢,不多说上代码:

ef set_func(func):
    def call_func(*args,**kwarg):
        print("这是权限验证1")
        print("这是权限验证2")
        func(*args,**kwarg)
    return call_func

@set_func
def test1(*args,**kwarg):
    print("----test1----",args)
    print("----test1----", kwarg)

test1(100,200,300,mm=100)

  一切都是水到渠成。那么再想一个问题,当同一个装饰器修饰不同函数时可以吗?当然可以,看代码:

from time import ctime, sleep

def timefun(func):
    def wrapped_func():
        print("%s called at %s" % (func.__name__, ctime()))
        func()
    return wrapped_func

@timefun
def foo():
    print("I am foo")

@timefun
def getInfo():
    return '----hahah---'

foo()
sleep(2)
foo()


print(getInfo())

运行结果:

foo called at Fri Nov  4 21:55:35 2016
I am foo
foo called at Fri Nov  4 21:55:37 2016
I am foo
getInfo called at Fri Nov  4 21:55:37 2016
None

     可以看出是可以的,那么下面再引出一个问题,有返回值的怎么办?所以为了让装饰器更加通用,最好在func处改为return func(),这样会更加通用。

     上面说了同一个装饰器修饰多个函数可以的,那么多个修饰器修饰同一个方法怎么办?代码如下:

def add_qx(func):
	print("---开始进行装饰权限1的功能---")
	def call_func(*args, **kwargs):
		print("---这是权限验证1----")
		return func(*args, **kwargs)
	return call_func


def add_xx(func):
	print("---开始进行装饰xxx的功能---")
	def call_func(*args, **kwargs):
		print("---这是xxx的功能----")
		return func(*args, **kwargs)
	return call_func


@add_qx
@add_xx
def test1():
	print("------test1------")


test1()

 结果如下:

 可以总结出一个规律,当有多个修饰器修饰同一函数时,执行结果是从上到下顺序执行的。

 那么在引申一下,装饰器可否装饰类?答案是可以的,代码如下:

class Test(object):
	def __init__(self, func):
		self.func = func

	def __call__(self):
		print("这里是装饰器添加的功能.....")
		return self.func()


@Test  # 相当于get_str = Test(get_str)
def get_str():
	return "haha"

print(get_str())

运行结果:

此种不太常用,这里再介绍一个知识点,__call__方法,可以直接使用类名加括号使用,就和使用函数一样。是不是很灵活。今天装饰器讲解到此结束

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值