python--装饰器

本文介绍了如何在Flask应用中使用装饰器简化session验证,以及Flask提供的before_request和errorhandler装饰器的作用。通过装饰器模式,可以在不修改原有代码的情况下,为函数增加额外功能,如权限检查和日志记录。
摘要由CSDN通过智能技术生成

python–装饰器

Flask已经学习很多基础知识,现在有一个问题:现在有一个 Flask 程序其中有3个路由和视图函数,如下:

from flask import Flask

app = Flask(__name__)  # type:Flask


@app.route("/login")
def login():
    return "Login"

@app.route("/index")
def index():
    return "Index"

@app.route("/home")
def home():
    return "Login"

if __name__ == '__main__':
	app.run("0.0.0.0", 5000)

如果登陆了,就可以访问 index 和 home 页面,如果没登录就跳转到 login 登录。要怎么解决呢?用 session 除了 Login 函数之外的所有函数里面全校验 session 是否登录,这样太麻烦了,现在只有3个函数,如果成百上千个函数就需要在所有函数中添加session校验;用装饰器,装饰器是一个很好的方案。

Decorator(修饰器)就是Python内部提供的一个语法便利,用于更加快捷、方法、直观地实现修饰器模式。修饰器模式会使用得代码结构比较复杂,而decorator则不存在这个问题。

一、装饰器模式

**Decorator(修饰器)**就是Python内部提供的一个语法便利,用于更加快捷、方法、直观地实现修饰器模式。修饰器模式会使用得代码结构比较复杂,而decorator则不存在这个问题。

在Python中,万物皆对象。(Everything in Python is an object.)

当你定义一个函数的时候,你就得到了一个函数对象,这个对象的引用就是函数名。通过函数名,你可以做很多事情:

# 定义一个加法函数
def add(a, b):
    return a + b
    
# 调用函数
sum1 = add(1, 2)

# 把函数赋值给其它变量
sum_of_two_num = add

# 通过其它变量调用add
sum2 = sum_of_two_num(2, 3)

print(sum1, sum2) # 打印 3 5

######################################和谐的分割线###################################
def double(x):
    return 2 * x
    
# 一个数字列表
nums = [1, 2, 3, 4, 5]

# 将每个数自乘以2
# map(func, iter)就是对iter中的每个元素e调用 func(e)
# 下面的代码相当于 double_nums = list(map(lambda x: 2 * x, nums))
dubled_nums = list(map(double, nums))

print(dubled_nums) # 打印 [2, 4, 6, 8, 10]

######################################和谐的分割线###################################

# 根据lan返回不同版本的greet函数
def getGreet(lan):
    if lan == "En":
        def greet(name):
            return "Hello " + name

    elif lan == "Es":
        #lambda是一种不需要名字(即标识符)、由一个单独表达式成的匿名内联函数,表达式会在调用时被求值。
        return lambda name: "Hola " + name
        
    else:
        return lambda name: "Ciao " + name
        
greet = getGreet("Es") # 获取西语版本的greet函数

# Say "Hello World" in Spanish
print(greet("Mondo")) # 打印 Hola Mondo

**若要求实现整数的四则运行函数,并且保证每个函数的参数都为整数,如果有至少一个参数不为整数,则直接返回0。**四则运行4个函数在参数合法性检测方面的行为是一样的,所以可以通过定义一个公共的参数检测函数来实现。

def arg_check(x):
    return type(x) == int

def add(a, b):
    if not arg_check(a) or not arg_check(b):
        return 0

    return a + b

这是常见的方法,就是在实现四则运算前做一个检测,但所有四则运算方法内都需要增加数字类型检测会过于繁琐。

一个优化的思路,就是利用**“修饰器模式”**。修饰器模式就是在不改变现有功能的代码的基础上,为功能增加额外的行为。

def arg_check(x):
    return type(x) == int

def add(a, b):
    return a + b

#装饰函数
def checker(func):
    def new_func(a, b):
         # 额外的功能
         if not arg_check(a) or not arg_check(b):
             return 0

         # 原来的功能
         return func(a, b)

    # 返回一个新的函数,这个函数增加了额外的功能
    # 并保留了原函数的功能
    return new_func

# 通过调用checker来为每个函数增加额外的行为
# 即对函数进行修饰
add = checker(add)

通过checker函数,用返回值来替代原函数,这就是装饰器模式。

二、decorator

通过装饰器模式就大概已经知道decorator怎么实现了,装饰器就是python通过装饰器模式的原理提供的一种语法便利

def arg_check(x):
    return type(x) == int

def checker(func):
    def new_func(a, b):
         # 额外的功能
         if not arg_check(a) or not arg_check(b):
             return 0

         # 原来的功能
         return func(a, b)

    # 返回一个新的函数,这个函数增加了额外的功能
    # 并保留了原函数的功能
    return new_func

@checker
def add(a, b):
    return a + b

这就是修饰器的使用方法了,可以看出:

def xx(a, b):
    # blabla

xx = checker(xx)

# 等价于
@checker
def xx(a, b):
    # blabla
三、带额外参数的Decorator
def arg_check(x):
    return type(x) == int

def checker(log="arithmatic.log"):
    
    def real_dec(func):
        def new_func(a, b):
             # 参数检测
             if not arg_check(a) or not arg_check(b):
                 return 0

             # 打印日志
             fout = open(log, mode="w")
             fout.write("called: %s(%d, %d)\n".format(func.__name__, a, b))
             fout.close()

             # 原来的功能
             return func(a, b)

        return new_func

    return real_dec

@checker("add.log")
def add(a, b):
    return a + b

通过这个方式,add每次被调用,都会分别向add.log写入一条日志;但无论我们是否提供参数,checker的括号都不可省略

四、flask中特殊的装饰器
from flask import Flask
from flask import request
from flask import redirect
from flask import session

app = Flask(__name__)  # type:Flask
app.secret_key = "DragonFire"


@app.before_request
def is_login():
    if request.path == "/login":
        return None

    if not session.get("user"):
        return redirect("/login")


@app.route("/login")
def login():
    return "Login"


@app.route("/index")
def index():
    return "Index"


@app.route("/home")
def home():
    return "Login"



if __name__ == '__main__':
    #启动的是 flask自带的服务器,也就是Werkzeug这个做WSGI 容器
	app.run("0.0.0.0", 5000)
    
    #启动的是wsgiref这个模块的 make_server做 WSGI容器。
    #make_server("0.0.0.0", 5000, app)

@app.before_request 也是一个装饰器,他所装饰的函数,都会在请求进入视图函数之前执行。

request.path 是来读取当前的url地址,如果是 /login 就允许直接通过 return None ,理解成通过放行。校验session中是否有user ,如果没有的话,证明没有登录,所以毫不留情的 redirect(“/login”) 跳转登录页面。

还有一个要提的 @app.before_first_request 它与 @app.before_request 极为相似或者说是一模一样,只不过它只会被执行一次。

使用**@app.before_request**装饰器可以很好的解决文章开头提出的问题。

@app.after_request :在响应(response)之前做出响应

@app.errorhandler() :重定义错误页面返回信息

比如:当404时则会执行下面的视图函数

@app.errorhandler(404)
def error404(error_info):
	return 三剑客+小儿子
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值