用最简单的例子了解装饰器

用最简单的例子了解装饰器

以下为作者个人理解。如不认同 ,欢迎留言。

1- 定义:
	定义我也说不上来, 大家自行百度
2- 作用:
		装饰器能在不大幅度修改原有代码的情况下添加功能
3- 推导步骤

1- 我这里有个 【查询函数】

def index():
    print('这里有好多内部信息, 严禁外泄')
    return 'ok'

2- 这时候我添加一个功能,只有指定的人才能看到这些数据, 下文称 【验证函数】

user_data  = [{'username': '张三', 'password': 'zhangsan'}, {'username': '李四', 'password': 'lisi'}, {'username': '王五', 'password': 'wangwu'}]

def login(u_name, p_word):
    data = {
        'code': -1,
        'msg': '验证未通过'
    }
    # 获取所有username和password
    print(user_data)
    # 方法一
    for d in user_data:
        if u_name in d['username']:
            # 用户名存在
            if p_word == d['password']:
                data = {
                    'code': 1,
                    'msg': '用户 {} 登录成功'.format(u_name),
                }
                return data
            else:
                data = {
                    'code': -1,
                    'msg': '密码不正确'
                }
                return data
        else:
            data = {
                'code': -1,
                'msg': '用户不存在'
            }
    return data

3- 问题来了, 怎么把这个限制添加到查询功能上呢
第一步:拿到 【查询函数】 和 【验证函数】。 了解函数的调用

我们需要了解, 一个函数写完之后并不是直接执行, 而是需要调用的
	def index():
    data = {
        'msg': '数据',
    }
    return data

写完之后, 其实并没有使用, 那我们如何使用呢。
	def index():
	    data = {
	        'msg': '数据',
	    }
	    return data
	    
	index()
对的, 那就是调用。如果这个你能理解, 那你对装饰器就了解一半了

第二步:在 【验证函数】 中 调用 【查询函数】

我们写了验证功能, 只需要在验证成功的时候调用我们的函数,功能就添加上去了, 不信你跑一下
	user_data  = [{'username': '张三', 'password': 'zhangsan'}, {'username': '李四', 'password': 'lisi'}, {'username': '王五', 'password': 'wangwu'}]
	
	def login(u_name, p_word):
	    data = {
	        'code': -1,
	        'msg': '验证未通过'
	    }
	    # 获取所有username和password
	    print(user_data)
	    # 方法一
	    for d in user_data:
	        if u_name in d['username']:
	            # 用户名存在
	            if p_word == d['password']:
	            	index()
	                data = {
	                    'code': 1,
	                    'msg': '用户 {} 登录成功'.format(u_name),
	                }
	                return data
	            else:
	                data = {
	                    'code': -1,
	                    'msg': '密码不正确'
	                }
	                return data
	        else:
	            data = {
	                'code': -1,
	                'msg': '用户不存在'
	            }
	    return data
我们在验证成功的情况下调用 【查询函数】 功能就添加上去了

第三步:将验证功能封装起来

我不可能在一个项目中找出每个 【查询函数】 并把 验证的代码套在函数上, 我们试试封装起来。代码如下
def decorate_login(f):
    def login(u_name, p_word):
        data = {
            'code': -1,
            'msg': '验证未通过'
        }
        # 从数据库中获取所有username和password
        user_data = get_sql_data()
        print(user_data)
        # 方法一
        for d in user_data:
            if u_name in d['username']:
                # 用户名存在
                if p_word == d['password']:
                    f()
                    data = {
                        'code': 1,
                        'msg': '用户 {} 登录成功'.format(u_name),
                    }
                    return data
                else:
                    data = {
                        'code': -1,
                        'msg': '密码不正确'
                    }
                    return data
            else:
                data = {
                    'code': -1,
                    'msg': '用户不存在'
                }
        return data
    return login
此时,我们只需调用decorate_login函数, 并将 【查询函数】 作为参数传进去就能做到在 【查询函数】 调用之前先验证。那又有一个问题了,我不可能在项目中找到每一个 【查询函数】 并把它替换成decorate_login函数。 

第五步:骚操作, 语法糖

到达这一步, 装饰器已经基本完成, 只剩下调用问题。如何调用呢。 没错,就是传说中的骚操作,语法糖。
我们只需要在 【查询函数】前, 添加 @decorate_login 这行代码, 装饰器就完成了。完整代码如下:
import pymysql


# 连接并读取数据库
def get_sql_data():
    # 连接数据库
    conn = pymysql.connect(host='localhost',port=3306,db='self_demo',user='root',password='rock1204.')
    # 创建一个游标
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    # 编写sql语句
    sql = 'select * from User'
    # 执行sql语句
    cursor.execute(sql)
    # 查看sql
    result = cursor.fetchall()


    # 执行语句
    try:
        conn.commit()
    except:
        print('执行不成功')
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    return result


# 登录验证 装饰器
def decorate_login(f):
    def login(u_name, p_word):
        data = {
            'code': -1,
            'msg': '验证未通过'
        }
        # 从数据库中获取所有username和password
        user_data = get_sql_data()
        print(user_data)
        # 方法一
        for d in user_data:
            if u_name in d['username']:
                # 用户名存在
                if p_word == d['password']:
                    f()
                    data = {
                        'code': 1,
                        'msg': '用户 {} 登录成功'.format(u_name),
                    }
                    return data
                else:
                    data = {
                        'code': -1,
                        'msg': '密码不正确'
                    }
                    return data
            else:
                data = {
                    'code': -1,
                    'msg': '用户不存在'
                }
        return data
    return login


# 主要功能
@decorate_login
def index():
    print('这里有好多内部信息')
    return 'ok'


index('张三', 'zhangsan')

数据库需要自己调通(或者用列表代替,列表在上面代码), 我们发现, 调用【查询函数】也能实现验证功能。只是需要将参数传入,提供给【验证函数】使用。
4- 练习

以上是 【查询函数】外面套一层验证用户的【验证函数】。先需要对输入的用户名和密码长度进行限制,用户名长度不能超过6位, 密码不能超过20位。添加一个装饰器。
参考代码如下:

import pymysql


# 连接并读取数据库
def get_sql_data():
    # 连接数据库
    conn = pymysql.connect(host='localhost',port=3306,db='self_demo',user='root',password='rock1204.')
    # 创建一个游标
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    # 编写sql语句
    sql = 'select * from User'
    # 执行sql语句
    cursor.execute(sql)
    # 查看sql
    result = cursor.fetchall()


    # 执行语句
    try:
        conn.commit()
    except:
        print('执行不成功')
    # 关闭游标
    cursor.close()
    # 关闭连接
    conn.close()
    return result


# 登录验证 装饰器
def decorate_login(f):
    def login(u_name, p_word):
        data = {
            'code': -1,
            'msg': '验证未通过'
        }
        # 从数据库中获取所有username和password
        user_data = get_sql_data()
        print(user_data)
        # 方法一
        for d in user_data:
            if u_name in d['username']:
                # 用户名存在
                if p_word == d['password']:
                    f()
                    data = {
                        'code': 1,
                        'msg': '用户 {} 登录成功'.format(u_name),
                    }
                    return data
                else:
                    data = {
                        'code': -1,
                        'msg': '密码不正确'
                    }
                    return data
            else:
                data = {
                    'code': -1,
                    'msg': '用户不存在'
                }
        return data
    return login


# 主要功能
@decorate_login
def index():
    print('这里有好多内部信息')
    return 'ok'


index('张三', 'zhangsan')