闭包和装饰器

闭包函数

闭包如何产生的?

  因为函数内部又有嵌套函数,
  嵌套函数定义:定义在内部的函数无法在全局被调用
  所以产生了闭包问题

def func1()
    def func2()
        a = 1
        return a
    func2()

闭包产生的问题?

  就是func1 拿不到func2 的变量a
  怎么才能拿到呢?
  我们知道,函数是第一类对象(第一类对象说白了你可以把函数当成变量使用),你可以把func1中的变量(func2)通过return返回

def func1()
    def func2()
        a = 1
        return a
    return func2

x = func1()    #这样就拿到了func2 并赋值给了变量x
x()        # x()等同于 func2()      看明白了吧    就得到了一个返回值a   这样就拿到func2 的变量a了

而如果:

def func1(para1):
    para1
    def func2():
        a = 1
        return para1 + a
    return func2

func1(5)    #如果把5传给func1    就会把def func2 这个函数打包,

注意内部函数:

def func2():
    a = 1
    return 5 + a

func1(5)()   #等同于func2()

就变相调用函数func2() 得到返回值 6

print(func1(5)())   # 6

如果func1(8), 那么func2打包后:

def func2()
        a = 1
        return 8 + a

每次调用func1,就会返回(打包)一个新的闭包实例

所以:

  闭包 = 函数 + 引用环境

  闭包:python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)

装饰器

装饰器函数:

  装饰器函数本质 就是闭包的一种应用

  装饰器功能目的 就是实现 不修改原函数及其调用方式的情况下对原函数功能进行扩展

def timmer(func): 
    def inner():
        print(1)
        func()          #内部函数引用外部函数的参数变量        产生闭包函数
        print(2)
    return inner

def func():
    print('hello')

timmer(func)  #得到 inner函数名
f = timmer(func)    # f = inner
f()       # inner()     
# 1
# hello
# 2

应用中涉及到的函数:

  被装饰函数
  装饰函数
  内嵌包装函数

装饰器书写格式:

def  wrapper(func):    ------------装饰函数
    def inner(*args,**kwargs):   ------------内嵌包装函数
        #功能添加(被装饰函数执行之前扩展的功能代码)(把这两行功能添加代码注释掉,等于去掉所有的装饰器)
        ret = func(*args,**kwargs)         
        #功能添加(被装饰函数执行之后扩展的功能代码)
        return ret
    return inner

使用:

@wrapper      #@wrapper 语法糖 等价于 func = wrapper(func) 
def func():    # 被装饰函数
    return 1111    #带返回

装饰器 开放封闭原则:

  1.对 扩展 开放 允许代码扩展、添加新功能。(修复 bug)

  2.对 修改 封闭 修改函数,有可能牵一发动全身

小示例:一次登录,处处使用

flag = True
def login(args):
    def inner():
        global flag
        if flag:         #第一次调用函数,进入登录,要输入用户名和密码   如果第一次调用函数用户名密码正确,  flag为False,不用进入登录
            username = input("Please enter your user name:")
            pwd = input("Please enter your password:")
            if username == 'kitty' and pwd == '123':
                print("Login successfully!")
                flag = False  #用户名密码正确,就把条件改变,
        if not flag:          #如果flag发生变化,说明登录成功,否则,就进不去if语句,执行不了args()
                args()
    return inner
@login                      #语法糖        
def article():
    print("Welcome to article!")
@login
def diary():
    print("Welcome to diary!")
article()
diary()
#Please enter your user name:kitty
# Please enter your password:123
# Login successfully!
# Welcome to article!
# Welcome to diary!

使用装饰器计算代码运行时间

import time
print(time.time())   #1970年1月1日00:00:00:000开始计秒

def timer(func):
    def inner():
        start_time = time.time()
        time.sleep(0.1)
        func()
        end_time = time.time()
        print(end_time - start_time)
    return inner
@timer
def func():
    print(1111)
func()
View Code

取消装饰器函数:

def outer(flag):
    def wrapper(func):
        def inner():
            if flag:                    #falg = False   就不执行扩展功能
                print("扩展功能")
            ret = func()
            if flag:                    ##falg = False   就不执行扩展功能
                print("扩展功能")
            return ret
        return inner
    return wrapper

@outer(False)
#@outer(True)
def func():
    print('kitty')
func()

多个装饰器装饰一个函数

def wrapper1(func):
    def inner():
        print(111)
        func()
        print(222)
    return inner

def wrapper2(func):
    def inner():
        print('aaa')
        func()
        print('bbb')
    return inner

@wrapper2
@wrapper1
def func():
    print('kitty')
func()

aaa
# 111
# kitty
# 222
# bbb
原文地址:https://www.cnblogs.com/jin-yuana/p/10024639.html