python3 装饰器

如果想在程序中加入恶意代码,装饰器是不错的选择!

  • 一来装饰器函数一般在主程序外定义,不易被发现;
  • 二来装饰器函数在主程序运行之前执行,可以在主程序运行之前,获得系统分配的资源.

装饰器的语法规则很有趣,可以在不改变原有函数代码的前提下进行扩展,实现程序的友好迭代升级

其实装饰器的功能不只是更改函数,如果你愿意,装饰器还能"智能"的选择函数

在网站的后台,有这样一种需求:需要把前端页面的请求分类处理:把形似(1345.html, 4567.html)等以数字命名的网页逻辑交由一个函数处理;把形似(index.html, center.html)等以字母命名的网页交由另一个函数处理;

直白的讲,就是对不同页面的请求进行分类处理.

对数据进行分类匹配,正则表达式是首选的方式!

我们先定义两个负责处理不同逻辑的函数,并附带"正则表达式"匹配规则的装饰器

# 匹配"字符名称网页"的函数
@route(r"[a-z]+\.html")
def char(file_name, url=None):
    print("收到了'名称为字符'的网页")
    print("接收的文件名为",file_name)
    print("匹配的正则url表达式为:",url)
    print("~"*20)

#匹配"数字名称网页"的函数
@route(r"[\d]+\.html")
def num(file_name, url=None):
    print("收到了'名称为数字'的网页")
    print("接收的文件名为",file_name)
    print("匹配的正则url表达式为:",url)
    print("~"*20)

然后定义装饰器函数

# route用于匹配函数式
def route(url):
    # set_func用于接收函数的引用
    def set_func(func):
        # 将正则表达式与函数绑定
        route_dic[url] = func
        print("--为route_dic--添加了一个键值对")
        # call_func用于创建新的函数,并将新函数返回,替换被修饰的旧函数
        def call_func(file_name, url):
            return func(file_name, url)
        return call_func
    return set_func

基础的装饰器定义为两层函数嵌套,外层负责接受原函数(被添加装饰器的函数)的引用,内层负责扩展原函数功能,最后外层函数将内层函数返回,返回的内层函数将替代原函数(被添加装饰器的函数)


我们这里的装饰器函数在基础装饰器的层面上又多套了一层负责判定的函数,这样我们的装饰器就有了"分类功能"

测试代码:

import re

# 用于存储"函数的引用" 与 "url正则表达式"的键值对
route_dic = dict()

# route用于匹配函数式
def route(url):
    # set_func用于接收函数的引用
    def set_func(func):
        # 预加载,将正则表达式与函数绑定
        route_dic[url] = func
        print("--为route_dic--添加了一个键值对")
        # call_func用于创建新的函数,并将新函数返回,替换被修饰的旧函数
        def call_func(file_name, url):
            return func(file_name, url)
        return call_func
    return set_func
        
@route(r"[a-z]+\.html")
def char(file_name, url=None):
    print("收到了'名称为字符'的网页")
    print("接收的文件名为",file_name)
    print("匹配的正则url表达式为:",url)
    print("~"*20)

@route(r"[\d]+\.html")
def num(file_name, url=None):
    print("收到了'名称为数字'的网页")
    print("接收的文件名为",file_name)
    print("匹配的正则url表达式为:",url)
    print("~"*20)

def match_func(file_name):
    for url, call_func in route_dic.items():
        ret = re.match(url, file_name)
        if ret:
            print("找到了页面")
            call_func(file_name,url)
        else:
            pass

def main():
    print("route字典的值为", route_dic)
    # 测试"名称为字符"的网页
    match_func("index.html")
    # 测试"名称为数字"的网页
    match_func("123.html")
if __name__ == "__main__":
    main()

运行结果

运行结果
运行结果

如上图所示,123.htmlindex.html都被分配到了对应的函数执行!


更深一点:

细心的人会发现,其实装饰器函数比主程序要更早的执行

  • 证据1:主程序在使用字典route_dic之前,未调用过route函数,但route_dic中却早已有了值,说明在main函数执行之前,route函数已经被调用过了;
  • 证据2:从以上程序的执行结果截图来看,添加键值对的操作在main函数执行之前,提前执行了两次,正好对应两个装饰器

如果想在程序中加入恶意代码,装饰器函数是不错的选择!

  • 一来装饰器函数一般在主程序外定义,不易被发现;
  • 二来装饰器函数在主程序运行之前执行,可以在主程序运行之前,获得系统分配的资源.


作者:_昭昭_
链接:http://www.jianshu.com/p/dee05d5dfb50
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @ 2017-09-13 22:26  大黑马  阅读(1153)  评论(0编辑  收藏  举报