python装饰器源代码_Python 装饰器详解

开放封闭原则:

开放对扩展

封闭修改源代码

改变了人家调用方式

装饰器结构

"""

默认结构为三层!!!每层返回下一层内存地址就可以进行执行函数,

传参:语法糖中的传参可以在地二层中进行判断传入。

第一层:传送语法糖中的参数

第二层:传送外部函数的名称

第三层:传送外部函数的参数

被装饰器装饰的函数名即使没有被调用(因为有@xxx,会触发运行装饰器),

(装饰器工厂函数)定义装饰器的代码已经运行了(最内部的那个函数并没有运行),

(把被装饰的原函数引用赋值给了装饰器内部的那个函数名),当下边通过该函数名调用时,

会调用到装饰器内部的那个函数()

装饰器:在不修改函数源代码的基础上,添加函数功能

"""

def Wrapper(*args,**kwargs): #获取`@Wrapper(args)`传入参数

def Outter(func_name): #获取装饰器所装饰函数的名称

def Inner(*args,**Kwargs): #获取`def func(*args,**kwargs):`的传入参数

ret = func_name(*args,**kwargs) #执行装饰器所装饰的函数

return ret #将返回值传给被装饰的函数

return Inner #返回`Inner`的内存地址,方便调用

return Outter #返回`Outter`的内存地址,方便调用

@Wrapper(args) #`func = Outter(func) = Wrapper(args)`装饰器进行传参

def func(*args,**kwargs): #定义被装饰函数

return func.__name__ #定义函数返回值

返回装饰器的被装饰函数名

from functools import wraps

def warpper(f):

@wraps(f) #显示被装饰的函数

def inner(*args,**kwargs):

# print(f.__name__)

print(f)

return inner #

def aa():

print(1)

aa = warpper(aa)

print(aa.__name__) # 显示被装饰的函数名

账户认证(简易版)

def Wrapper(auth_type): #默认使用Wrapper名称,获取语法糖的参数

def Outer(func_name): #获取传入参数的名称

def file(*args,**kwargs): #获取传入参数的参数

print('这是在file函数中')

ret = func_name(*args,**kwargs)

print('file函数装饰完毕')

return ret

def net(*args,**kwargs):

print('这个是在网络函数中')

ret = func_name(*args,**kwargs)

print('网络函数执行结束')

return ret

if auth_type == 'localfile': #对传入参数进行判断返回不同结果

return file

elif auth_type == 'net':

return net

else:

print('该函数没有被装饰')

return Outer

@Wrapper(auth_type='net') #语法糖进行传参

def Login(username):

print(f'Welcome {username} Login.')

Login('longlong') #大神登陆啦!

Python 装饰器装饰类中的方法

本文介绍如何使用Python的装饰器装饰一个类的方法,同时在装饰器函数中调用类里面的其他方法。本文以捕获一个方法的异常为例来进行说明。

有一个类Test, 它的结构如下:

class Test(object):

def __init__(self):

pass

def revive(self):

print('revive from exception.')

# do something to restore

def read_value(self):

print('here I will do something.')

# do something.

在类中有一个方法read_value(),这个方法在多个地方被调用。由于某些原因,方法read_value()有可能随机抛出Exception导致程序崩溃。所以需要对整个方法做try ... except处理。最丑陋的做法如下面的代码所示:

class Test(object):

def __init__(self):

pass

def revive(self):

print('revive from exception.')

# do something to restore

def read_value(self):

try:

print('here I will do something.')

# do something.

except Exception as e:

print(f'exception {e} raised, parse exception.')

# do other thing.

self.revive()

这样写虽然可以解决问题,但是代码不Pythonic。

使用装饰器来解决这个问题,装饰器函数应该写在类里面还是类外面呢?答案是,写在类外面。那么既然写在类外面,如何调用这个类的其他方法呢?

首先写出一个最常见的处理异常的装饰器

def catch_exception(origin_func):

def wrapper(*args, **kwargs):

try:

u = origin_func(*args, **kwargs)

return u

except Exception:

return 'an Exception raised.'

return wrapper

class Test(object):

def __init__(self):

pass

def revive(self):

print('revive from exception.')

# do something to restore

@catch_exception

def read_value(self):

print('here I will do something.')

# do something.

这种写法,确实可以捕获到origin_func()的异常,但是如果在发生异常的时候,需要调用类里面的另一个方法来处理异常,这又应该怎么办?答案是给wrapper增加一个参数:self.

代码变为如下形式:

def catch_exception(origin_func):

def wrapper(self, *args, **kwargs):

try:

u = origin_func(self, *args, **kwargs)

return u

except Exception:

self.revive() #不用顾虑,直接调用原来的类的方法

return 'an Exception raised.'

return wrapper

class Test(object):

def __init__(self):

pass

def revive(self):

print('revive from exception.')

# do something to restore

@catch_exception

def read_value(self):

print('here I will do something.')

# do something.

通过添加一个self参数,类外面的装饰器就可以直接使用类里面的各种方法,也可以直接使用类的属性。

使用类来写装饰器

前两天发现了装饰器可以直接使用类来写,分享一下,需要用类里面的__call__方法,__call__方法就是可以把这个实例当成一个函数来调用,如果正常使用类里面的方法的话,实例方法要先实例化类,然后才能调用,静态方法、类方法则需要用类名或者实例化之后的对象来调用,而实例化之后的这个对象,是不能被调用的,__call__方法就是把这个实例变成一个可以调用的对象,也就是说实例化之后,这个对象就可以和一个普通函数一样被调用。

示例代码如下:

class Foo:

def __call__(self, *args, **kwargs):

print('call....')

def test(self):#

print('test....')

if __name__ == '__main__':

t = Foo()#实例化类

t.test()#正常调用实例方法

t()#直接调用实例化之后的对象

理解了上面的之后,就可以使用class来写一个装饰器了,计算程序的运行时间,当然思想和以前用函数写装饰器是一样的

class Fuck(object):

def __init__(self, func):

self.func = func

def __call__(self, *args, **kwargs):

import time

start_time = time.time()

res = self.func(*args, **kwargs)

end_time = time.time()

print('the function "%s" run time is %s' % (self.func.__name__,

(end_time - start_time)))

return res

@Fuck

def run(name):

import time

time.sleep(1)

return 'sb_%s' % name

print(run('hyf'))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值