python的装饰器
面向对象的理解:一切皆对象
def test(name='ksks14'):
'''这是是注释'''
return 'hello '+name
print(test.__name__)
print(test.__doc__)
print(test())
test
这是是注释
hello ksks14
'''
将test函数赋值给另一个值
'''
# 注意赋值给的名而不是整个函数
new_test=test
print(new_test.__name__)
print(new_test.__doc__)
print(new_test())
test
这是是注释
hello ksks14
结果说明虽然是赋值,但实际上是类似于一个指向的作用
- 这时候删除掉test函数试试,报错
进一步走,python支持在函数中定义另外一个函数。
def test(name="test"):
print("Enter a function:test")
def test_1(name="test_1"):
print("Enter a function:test_1")
def test_2(name="test_2"):
print("Enter a function:test_2")
test_1()
test_2()
test()
Enter a function:test
Enter a function:test_1
Enter a function:test_2
进一步走,函数中自然也可以返回函数
def test(name="test"):
def test_1():
return "Enter a function:test_1"
def test_2():
return "Enter a function:test_2"
if name=="test":
return test_1()
else:
return test_2()
test("test")
'Enter a function:test_1'
总结发现,对于python的函数,如果将小括号放在后面就会执行,而如果单用名字则可以进行传递。既然可以进行传递,那么就可以将函数作为参数传递。
def out_func(func):
def wrap():
print("外层在执行函数前")
func()
print("外层在执行函数后")
# 这里返回函数名,用来传递测试
return wrap
def test_wrap():
print("执行函数")
test = out_func(test_wrap)
test()
外层在执行函数前
执行函数
外层在执行函数后
def out_func(func):
def wrap():
print("外层在执行函数前")
func()
print("外层在执行函数后")
# 这里返回函数名,用来传递测试
return wrap
@out_func
def test_wrap():
print("执行函数")
test_wrap()
外层在执行函数前
执行函数
外层在执行函数后
可以分析得到,在利用@之后,再次执行了一次封装,所以又多了两行外函数的输出同时使用了@之后可以直接调用test_wrap()
但是这里存在问题,输出name试试
print(test_wrap.__name__)
wrap
这里想要的应该是out_func而不是wrap,显然被修改了。
from functools import wraps
def out_func(func):
@wraps(func)
def wrap():
print("外层在执行函数前")
func()
print("外层在执行函数后")
# 这里返回函数名,用来传递测试
return wrap
@out_func
def test_wrap():
print("执行函数")
test_wrap()
print(test_wrap.__name__)
外层在执行函数前
执行函数
外层在执行函数后
test_wrap
显然这获取到了函数在修饰前的name,@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。
from functools import wraps
def logit(func):
@wraps(func)
# 这里的参数会传入到addition_func
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logit
def addition_func(x):
"""Do some math."""
return x + x
result = addition_func(4)
print(result)
addition_func was called
8
接着我们来看web登录状态判断的操作
import datetime
from functools import wraps
import pytz
from django.contrib import messages
from django.shortcuts import render, redirect, get_object_or_404
def is_login(func):
@wraps(func)
# 这里需要传入一个request
def wrapper(request,*args,**kwargs):
# 通过session获取一个user,进行判断
user=request.session.get("user",None)
if user:
return func(request,*args,**kwargs)
else:
messages.error(request, "用户未登录,请先登录!")
# 回退到登录操作
return redirect(reverse('login'))
return wrapper
# 这里通过函数装饰器进行用户判断。
@is_login
def index(request):
return redirect(reverse('play_list'))