闭包(closure)是函数式编程的重要的语法结构。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。
如果在一个内嵌函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内嵌函数可被认为是闭包。
定义在外部函数内但由内部函数引用或者使用的变量称为自由变量。
创建闭包需满足以下几点:
1、必有有一个内嵌函数
2、内嵌函数必须引用外部函数中的变量
3、外部函数的返回值必须是内嵌函数
嵌套函数也就是在函数体内创建一个函数(对象),这在python中是合法的。
def outer():
x = 1
def inner():
print(x) #1
inner() #2
outer()
#1处,解释器要在本地寻找一个x的本地变量,寻找失败,会继续在上层的作用域里面寻找,这个上层的作用域定义在另外一个函数里面。对函数outer来说,x就是一个本地变量,函数inner可以访问封闭的作用域(至少可以读和修改值)。#2处,inner也仅仅是一个遵循python 变量解析规则的变量名,python解释器会优先在outter的作用域里面对变量名inner查找匹配的变量。
def outer(x):
def inner():
print(x)
return inner
print1 = outer(1)
print1()
变量x是函数outer的一个传入参数,是outer的一个本地变量,只有当函数outer运行的时候才存在,但是由于闭包特性的存在即嵌套定义在非全局作用域里面的函数能够记住它在被定义的时候它所处的封闭命名空间。被函数记住的封闭作用域-能够被用来创建自定义的函数,本质上来说是一个硬编码的参数。
装饰器
装饰器本身就是一个闭包,把一个函数当做参数然后返回一个替代版的函数。
class Coordinate(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return "Coord: " + str(self.__dict__)
def add(a, b):
return Coordinate(a.x + b.x, a.y + b.y)
def sub(a, b):
return Coordinate(a.x - b.x, a.y - b.y)
one = Coordinate(100, 200)
two = Coordinate(300, 200)
add(one, two)
Coord: {'y': 400, 'x': 400}
def wrapper(func):
def checker(a, b): # 1
if a.x < 0 or a.y < 0:
a = Coordinate(a.x if a.x > 0 else 0, a.y if a.y > 0 else 0)
if b.x < 0 or b.y < 0:
b = Coordinate(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0)
ret = func(a, b)
if ret.x < 0 or ret.y < 0:
ret = Coordinate(ret.x if ret.x > 0 else 0, ret.y if ret.y > 0 else 0)
return ret
return checker
add = wrapper(add)
sub = wrapper(sub)
sub(one, two)
Coord: {'y': 0, 'x': 0}
add(one, three)
Coord: {'y': 200, 'x': 100}
使用@标识符将装饰器应用的函数,只需要在函数定义前加上@和装饰器的名称
add = wrapper(add)
@wrapper
def add(a, b):
return Coorfinate(a.x+b.x, a.y+b.y)
被装饰的函数不带参数
def login_required(func):
def wrapper():
if user['is_login'] == True:
func()
else:
print('跳转到登录页面')
return wrapper
@login_required #相当于 login_required(edit_user)
def edit_user():
print('用户名修改成功')
@login_required #相当于 login_required(add_article)
def add_article():
print('添加文章成功')
edit_user() #相当于 login_required(edit_user)()
add_article() #相当于 login_required(add_article)()
被装饰的函数带有参数
def login_required(func):
def wrapper(*args,**kwargs):
if user['is_login'] == True:
func(*args,**kwargs)
else:
print('跳转到登录页面')
return wrapper
@login_required
def edit_user(username):
print('用户名修改成功:%s'%username)
edit_user()
带参数的装饰器
def login_required(site='front'):
def outter_wrapper(func):
def inner_wrappre(*args,**kwargs):
if site == 'front':
if user['is_login'] == True:
print('进入到前台了')
func(*args,**kwargs)
else:
print('跳转到前台的首页')
else:
if user['is_login'] == True:
print('进入到后台了')
func(*args,**kwargs)
else:
print('跳转到后台的首页')
return inner_wrappre
return outter_wrapper
@login_required('front')
def edit_user():
print('用户名修改成功')
@login_required('front')
def add_article():
print('添加文章成功')
edit_user()
wraps装饰器
使用wraps装饰器,既可以保留函数的一些属性比如__name__
from functools import wraps
def login_required(func):
@wraps
def wrapper(*args,**kwargs):
if user['is_login'] == True:
func(*args,**kwargs)
else:
print('跳转到登录页面')
return wrapper
@login_required
def edit_user(username):
print('用户名修改成功:%s'%username)
edit_user()
print(edit_user.__name__)
# 打印edit_user