闭包
什么是闭包?闭包的概念就是当我们在函数内定义一个函数时,这个内部函数使用了外部函数的临时变量,且外部函数的返回值是内部函数的引用时,我们称之为闭包。
闭包再理解?内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。
nonlocal关键字?显式的指定变量不是闭包的局部变量
优点: 闭包也具有提高代码可复用性的作用
闭包的一个常用场景就是装饰器
闭包需要满足的三个条件:
1. 函数内定义一个函数
2. 内部函数使用了外部函数的临时变量
3. 外部函数的返回值是内部函数的引用(指的就是内部的函数名)
闭包案例:一元线性函数
def line_conf(a, b):
def line(x): # 闭包条件1:函数内定义一个函数
return a * x + b # 闭包条件2:内部函数使用了外部函数的临时变量a , b
return line # 闭包条件3:外部函数的返回值是内部函数的引用(指的就是内部的函数名)
# 注意函数名后面没有()
# 一元线性方程x+1
line1 = line_conf(1, 1)
# 一元线性方程3x+2
line2 = line_conf(3, 2)
# 一元线性方程4x+3
line3 = line_conf(4, 3)
loopCount = 100
y1 = [line1(item) for item in range(loopCount)]
y2 = [line2(item) for item in range(loopCount)]
y3 = [line3(item) for item in range(loopCount)]
#图形绘制(pyecharts==0.5.11)===导入绘制折线图的类
from pyecharts import Line
# 创建绘制折线图的对象lineObj
x = list(range(loopCount)) # x轴坐标必须是一个列表;
lineObj = Line(title="一元线性方程图形展示")
lineObj.add(name='y=x+1', x_axis=x, y_axis=y1)
lineObj.add(name='y=3x+2', x_axis=x, y_axis=y2)
lineObj.add(name='y=4x+3', x_axis=x, y_axis=y3)
# 将绘制的图形显示为html文件
lineObj.render('./doc/line.html')
注意:绘图模块需要进行包的下载:
./pip install pyecharts==0.5.11
./pip install pyecharts_snapshot
用浏览器打开line.html文件查看绘制的图形
装饰器Decorator
装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景, 比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。
为什么需要装饰器?
写代码要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
1)封闭:已实现的功能代码块
2)开放:对扩展开发
import time
age = 19
def is_adult(fun):
def wrapper():
start_time = time.time()
if age >= 18:
fun()
else:
print("未成年")
end_time = time.time()
print("程序运行时间:%.3f" % (end_time - start_time))
# 返回的是函数的引用
return wrapper
@is_adult # 语法糖:music = is_adult(music)
def music():
time.sleep(1)
print("正在听音乐.....")
@is_adult
def videos():
print("正在看视频.....")
@is_adult
def game():
print("正在玩游戏.....")
# 此处省略1000个函数模块
music()
# 运行结果
正在听音乐.....
程序运行时间:1.001
装饰器(decorator)功能
1. 引入日志
2. 函数执行时间统计
3. 执行函数前预备处理
4. 执行函数后清理功能
5. 权限校验等场景
6. 缓存
引入日志的装饰器
# 引入日志
import os
import time
import sys
# 装饰器: 用来添加日志信息的
def add_log(fun):
"""
May 26 09:50:14 foundation0 systemd: Removed slice user-0.slice.*args
ar
"""
def wrapper(*args, **kwargs):
# 获取被装饰的函数的返回值
result = fun(*args, **kwargs)
# 返回当前的字符串格式时间
now_time = time.ctime()
# 获取主机名 nodename='foundation0.ilt.example.com'
hostname = os.uname().nodename.split('.')[0]
# 运行的程序
process_full_name = sys.argv[0]
process_name = os.path.split(process_full_name)[-1]
# 日志内容
# info = "正在运行程序: " + str(fun)
# 获取函数名: 函数名.__name__
info ="函数[%s]的运行结果为%s" %(fun.__name__, result)
log = " ".join([now_time, hostname, process_name, info])
print(log)
return result
return wrapper
@add_log # 语法糖====music = add_log(music)
def music():
time.sleep(1)
print("正在听音乐.....")
@add_log
def add(x, y):
return x+y
@add_log
def roll(name, age, **kwargs):
print(name, age, kwargs)
roll(name='fentiao', age=10, province='陕西', gender='男')
# 运行结果
fentiao 10 {'province': '陕西', 'gender': '男'}
Thu Jun 6 01:45:45 2019 foundation70 闭包.py 函数[roll]的运行结果为None
如何编写通用装饰器(重要)
# *****************非常重要**************
def decorator(fun):
def wrapper(*args, **kwargs): # args, kwargs是形参
# 在函数之前做的操作
res = fun(*args, **kwargs) # *args, **kwargs是实参, *args, **kwargs是在解包
# 在函数之后添加操作
return res
return wrapper
@装饰器的名字
@add_log ======> add=add_log(add)
def add():
pass
add()
多个装饰器
# 1). 判断用户是否登录?
# 2). 判断用户是否有权限?
# 系统中的用户信息;
db = {
'root': {
'name': 'root',
'passwd': 'westos',
'is_super': 0 # 0-不是 1-是
},
'admin': {
'name': 'admin',
'passwd': 'westos',
'is_super': 1 # 0-不是 1-是
}
}
# 存储当前登录用户的信息;
login_user_session = {}
def is_login(fun):
"""
判断用户是否登录, 如果没有登录,先登录
:param fun:
:return:
"""
def wrapper1(*args, **kwargs):
if login_user_session:
result = fun(*args, **kwargs)
return result
else:
print("跳转登录".center(50, '*'))
user = input("User: ")
passwd = input('Password: ')
if user in db:
if db[user]['passwd'] == passwd:
login_user_session['username'] = user
print('登录成功')
# ***** 用户登录成功, 执行删除学生的操作;
result = fun(*args, **kwargs)
return result
else:
print("密码错误")
else:
print("用户不存在")
return wrapper1
def is_permission(fun):
def wrapper2(*args, **kwargs):
print("判断是否有权限......")
current_user = login_user_session.get('username')
permissson = db[current_user]['is_super']
if permissson == 1:
result = fun(*args, **kwargs)
return result
else:
print("用户%s没有权限" % (current_user))
return wrapper2
"""
**** 被装饰的过程:
1). delete = is_permission(delete) # delete = wrapper2
2). delete = is_login(delete) # delete = is_login(wrapper2) # delete = wrapper1
"""
@is_login # delete = is_login(delete)
@is_permission
def delete():
return "正在删除学生信息"
"""
*******被调用的过程:
delete() ------> wrapper1() ---> wrapper2() ---> delete()
"""
result = delete()
print(result)
# 运行结果
***********************跳转登录***********************
User: admin
Password: westos
登录成功
判断是否有权限......
正在删除学生信息
***********************跳转登录***********************
User: root
Password: westos
登录成功
判断是否有权限......
用户root没有权限
None
带参数的装饰器
如果装饰器需要传递参数, 在原有的装饰器外面嵌套一个函数即可
# 如果装饰器需要传递参数, 在原有的装饰器外面嵌套一个函数即可
def auth(type):
def wrapper1(fun):
def wrapper(*args, **kwargs):
if type == 'local':
user = input("User:")
passwd = input("Passwd:")
if user == 'root' and passwd == 'westos':
result = fun(*args, **kwargs)
return result
else:
print("用户名/密码错误")
else:
print("暂不支持远程用户登录")
return wrapper
return wrapper1
"""
# python中装饰器的语法糖结构: @funName ===>
# python中装饰器结构如果为@funName() ====> 默认跟的不是函数名, 先执行改函数, 获取函数返回结果 ====》 @funNameNew
@函数名 add=函数名(add)
@函数名() @新的函数名
"""
@auth(type='local')
def home():
print("这是主页")
home()
# 运行结果
User:root
Passwd:westos
这是主页
官方装饰器案例
https://wiki.python.org/moin/PythonDecoratorLibrary