Python之装饰器

闭包

什么是闭包?闭包的概念就是当我们在函数内定义一个函数时,这个内部函数使用了外部函数的临时变量,且外部函数的返回值是内部函数的引用时,我们称之为闭包。

闭包再理解?内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。

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 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值