首页 > 技术文章 > 6.装饰器

journeyer-xsh 2020-07-07 14:19 原文

一、闭包

1.1 什么是闭包?

闭包有什么作用。

  • 闭包只能存在嵌套函数中。
  • 内层函数对外层函数非全局变量的引用(使用),就会形成闭包。

被引用的非全局变量也称作自由变量,这个自由变量会与内层函数产生一个绑定关系,自由变量不会再内存中消失。

闭包的作用:保证数据的安全。

闭包的应用

  1. 可以保存一些非全局变量但是不易被销毁、改变的数据。
  2. 装饰器。

如何判断一个嵌套函数是不是闭包?

  • 闭包只能存在嵌套函数中。
  • 内层函数对外层函数非全局变量的引用(使用),就会形成闭包。

二、装饰器

开放封闭原则:

  • 开放:对代码的拓展

  • 封闭:对源码的修改是封闭的,源代码不应该被修改,如已经实现的的函数等

  • 装饰器:在不改变原函数的代码以及调用方式的前提下,为其增加新的功能

  • 装饰器就是一个函数

装饰器

在代码运行期间动态增加功能的方式。

# 用户可以直接登录
def home():
    login()
    print('首页')

def movie():
    print('电影')

现在要做登录验证:

def login():
    print('登录验证')

def home():
    login()		# 这里做了登录验证
    print('首页')

def movie():
    print('电影')

在home函数中做了登录验证,但是破坏了开放封闭原则,改变了原来写好的代码

def login(func):
    print('登录验证')
    func()


def home():
    print('首页')

def movie():
    print('电影')
    
home()
login(movie)

以上改写也不好,修改了调用方式,需要认证的模块都需要修改调用方式。需要不改变原功能代码,又不改变原有调用方式,还能加上认证的代码改写。

def login(func):
    print('登录验证')
    func()
    return


def home():
    print('首页')

def movie():
    print('电影')
    
home()
lo = login(movie)
lo()

这里不改变函数的调用方式,也不违反开放--封闭原则,但是lo = login(movie)就会执行movie()函数,可以在外面再嵌套一层,使lo = login(movie)只调用外层函数,不执行movie()函数。

def login(func):
    def inner():
        print('登录验证')
        func()
    return inner

def home():
    print('首页')

def movie():
    print('电影')
    
home()
lo = login(movie)
lo()

这样就间接调用movie()函数了,lo = login(movie)改写为@login,

def login(func):
    def inner():
        print('登录验证')
        func()
    return inner

def home():
    print('首页')
@login
def movie():
    print('电影')
    
home()
movie()		# 等同于lo = login(movie)

定义一个能打印时间的装饰器

import datetime

def log(func):   # 装饰器接受一个函数作为参数,并返回一个函数名
    def wrapper(*args, **kwargs):
        print('call %s(): ' % func.__name__)
        return func(*args, **kwargs)
    return wrapper

@log  # 运用@语法把装饰器放置在函数定义处
def now():
    print(datetime.datetime.now())

now()
"""
call now(): 
2020-07-06 21:56:43.968471
"""

带参数的装饰器

def login(func):
    def inner(*args, **kwargs):
        print('登录')
        func(*args,**kwargs)
    return inner

@login
def funca(name):
    print('欢迎', name)

funca('asdw')
# 登录
# 欢迎 asdw
# 装饰器加参数
def logger(path):
    def log(func):
        def inner(*args, **kwargs):
            ret = func(*args, **kwargs)
            with open(path, encoding='utf-8', mode='wt')as f1:
                f1.write('%s 执行了%s'%(time.strftime('%Y-%m-%d %H:%M:%S'), func.__name__))
            return ret
        return inner
    return log
@logger('auth.log')
def login():
    print('登录')

@logger('auth.log')
def register():
    print('注册')

@logger('auth.log')
def show_goods():
    print('查看商品信息')
    
@logger('operate.log')
def add_goods():
    print('购物车')

login()

推荐阅读