python装饰器深度讲解_python装饰器的深度探究

1.讲装饰器一般讲到这种代码就可以了,但这篇博客会介绍更多:

def deco(func):

def wrapper():

print("start")

func() #调用函数

print("end")

return wrapper

@deco

def myfun():

print "run"

myfun()

2.装饰任意参数的函数:

def deco(func):

def warpper(*args,**kwargs):

print("start")

func(*args,**kwargs)

print("end")

return warpper

@deco

def myfun1(param1):

print "run with param %s"%(param1)

装饰器会重写函数的名字和注释文档,@wraps(func)可以解决这个问题

from functools import wraps

def deco(func):

@wraps(func)

def warpper(*args,**kwargs):

print("start")

func(*args,**kwargs)

print("end")

return warpper

3.django自定义装饰器实现登录验证

def Check_Login(func): #自定义登录验证装饰器

def warpper(request,*args,**kwargs):

is_login = request.session.get('IS_LOGIN', False)

if is_login:

func(request,*args,**kwargs)

else:

return HttpResponseRedirect("/polls/login_user")

return warpper

def login_user(request):

if request.method == 'POST':

form = LoginForm(request.POST)

if form.is_valid():

# 获取post数据,例如 {'username': u'yang1', 'password': 111}

all_data = form.clean()

u = all_data['Form_username']

p = all_data['Form_password']

exist = User.objects.filter(username = u,password = p).first()

if exist:

request.session['IS_LOGIN'] = True #设置session的随机字段值

request.session['uname'] = exist.username #设置uname字段为登录用户

return HttpResponseRedirect('/polls/home')

else:

return HttpResponse("账户或密码错误")

else:

form = LoginForm()

return render(request, 'polls/login_user.html', {'form': form})

@Check_Login

def home(request):

username = request.session.get('uname', False) #获取登录用户名

return render(request, 'polls/home.html', {'username': username})

4.带参数的装饰器

装饰器接受一个函数作为参数,这个毋庸置疑.但是有时候我们需要装饰器接受另外的参数,

此时需要再加一层函数,实际上是定义了一个生成装饰器的工厂函数,

调用它,搭配需要的参数,来返回合适的装饰器.

from functools import wraps

def logit(logfile='out.log'):

def logging_decorator(func):

@wraps(func)

def wrapped_function(*args, **kwargs):

log_string = func.__name__ + " was called"

print(log_string)

# 打开logfile,并写入内容

with open(logfile, 'a') as opened_file:

# 现在将日志打到指定的logfile

opened_file.write(log_string + '\n')

return func(*args, **kwargs)

return wrapped_function

return logging_decorator

@logit()

def myfunc1():

pass

5.装饰器类

比方说有时你只想打日志到一个文件;

而有时你想把引起你注意的问题发送到一个email,同时也保留日志,留个记录.

from functools import wraps

class logit(object):

def __init__(self, logfile='out.log'):

self.logfile = logfile

def __call__(self, func):

@wraps(func)

def wrapped_function(*args, **kwargs):

log_string = func.__name__ + " was called"

print(log_string)

# 打开logfile并写入

with open(self.logfile, 'a') as opened_file:

# 现在将日志打到指定的文件

opened_file.write(log_string + '\n')

# 现在,发送一个通知

self.notify()

return func(*args, **kwargs)

return wrapped_function

def notify(self):

# logit只打日志,不做别的

pass

使用类装饰器主要依靠类的__call__方法,当使用 @ 形式将装饰器附加到函数上时,

就会调用此方法.这个实现有一个附加优势,在于比嵌套函数的方式更加整洁.

给 logit 创建子类,来添加 email 的功能:

class email_logit(logit):

'''

一个logit的实现版本,可以在函数调用时发送email给管理员

'''

def __init__(self, email='admin@myproject.com', *args, **kwargs):

self.email = email

super(email_logit, self).__init__(*args, **kwargs)

def notify(self):

# 发送一封email到self.email

# 这里就不做实现了

pass

从现在起,@email_logit将会和@logit产生同样的效果,

但是在打日志的基础上,还会多发送一封邮件给管理员.

6.装饰器的执行顺序总结

def decorator_a(func):

print('Get in decorator_a')

def inner_a(*args, **kwargs):

print('Get in inner_a')

return func(*args, **kwargs)

return inner_a

def decorator_b(func):

print('Get in decorator_b')

def inner_b(*args, **kwargs):

print('Get in inner_b')

return func(*args, **kwargs)

return inner_b

@decorator_a

@decorator_b

def f(x):

print('Get in f')

return x * 2

当你不调用就这么执行时,返回结果是:

Get in decorator_b

Get in decorator_a

当你调用了f(1),返回结果是:

Get in decorator_b

Get in decorator_a

Get in inner_a

Get in inner_b

Get in f

所以:定义过程是自下向上,执行顺序是自上向下.

还有一个,有点深,看不懂,用到的时候再研究.

参考地址:http://www.runoob.com/w3cnote/python-func-decorators.html

参考地址:https://www.cnblogs.com/honey-badger/p/8978168.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值