python中闭包的概念以及装饰器介绍

1、什么是闭包python

  闭包(closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即便已经离开了创造它的环境也不例外。另外一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。以上两种解释都太抽象了。还有一种比较容易的理解方式:当一个函数内部嵌套另外一个函数,内部函数体用到了外部函数的局部变量,而且外部函数的返回结果是内部函数名(或者说是内部函数对象),这样在执行外部函数时获得的是内部函数对象,此时虽然外部函数已经结束,但接下来继续执行内部函数时,内部函数仍能访问到所引用的外部函数的那个局部变量,也就是说此时外部函数虽然执行完毕,但内存并无释放,还需等待内部函数执行完毕后才释放内存。这种现象就叫作闭包。数据库

def outer(name):
    def inner(age):
        print("name:", name, "age:", age)  # 内部函数inner调用了外部函数outer的变量name
    return inner   # 结果返回的时inner对象
f = outer("lilei")   # 执行outer函数获得的是inner对象,至关于f = inner
f(18)  # 至关于执行inner(18)
结果:
name: lilei age: 18

咱们能够经过__closure__属性来查看函数是否存在闭包,若是存在,则返回一个cell对象,而且经过cell对象能够查出闭包中所包含的全部外部变量。若是函数不存在闭包,则返回None.后端

def outer(name):
    def inner(age):
        print("name:", name, "age:", age)  # 内部函数inner调用了外部函数outer的变量name
    return inner   # 结果返回的时inner对象
f = outer("lilei")   # 执行outer函数获得的是inner对象,至关于f = inner
f(18)  # 至关于执行inner(18)
print(f.__closure__)
print(f.__closure__[0].cell_contents)
结果:
name: lilei age: 18
(<cell at 0x02E3EF10: str object at 0x02E4FAA0>,)
lilei

def outer(name,age):
    print("name:", name, "age:", age)
outer("lilei",18)
print(outer.__closure__)
结果:
name: lilei age: 18
None

2、闭包的应用——装饰器闭包

   python装饰器本质上就是一个函数,它可让其余函数在不须要作任何代码变更的前提下增长额外的功能,装饰器的返回值也是一个函数对象。装饰器函数的外部函数传入咱们要装饰的函数名字,返回通过装时候函数的名字,内层函数(闭包)负责修饰被修饰的函数。ide

  一、实质:是一个函数;函数

  二、参数:是你要装饰的函数名(并不是函数调用);学习

  三、返回:是装饰完的函数名(也非函数调用);网站

  四、做用:为已经存在的对象添加额外的功能;spa

  五、特色:不须要对对象作任何的代码上的改动。code

 

  说了这么多,装饰器到底有什么做用呢?python装饰器就是用于拓展原来的函数功能的一种函数,这个函数的特殊之处在于台的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数代码的前提下给函数增长新的功能。通常而言咱们想要拓展原来的函数功能,最直接的办法就是侵入代码里面修改,但这种方法有弊端,由于修改源代码不能保证源代码的其余模块功能的有效性。而且修改源代码还违反了软件开发中的一个原则”开放-封闭“原则,简单来讲,它规定已经实现功能的代码不该该被修改,但能够被扩展。即:封闭,已经实现的功能代码块不该该被修改 开放,对现有功能的扩展开放。

  举例:好比你是一家视频网站的后端开发工程师,大家网站的python专区有如下三种学习板块:

  一、写法一

account = {
    "is_authenticated": False,  # 用户登录成功就把它改为True
    "username": "lilei",  # 数据库中的用户信息
    "pass_word": "123"  # 数据库中的用户密码
}

def login():
    if account["is_authenticated"]  == False:
        user_name = input("user:").strip()
        password = input("password:").strip()
        if user_name == account["username"] and password == account["pass_word"]:
            print("welcome login....")
            account["is_authenticated"] = True
        else:
            print("wrong username or password")
    if account["is_authenticated"] == True:
        print("已经过验证...")

def home():
    print("python专区".center(30, "-"))
def first_stage():
    print("python初级阶段学习视频".center(30, "-"))
def second_stage():
    login()
    print("python中级阶段学习视频".center(30, "-"))
def third_stage():
    login()
    print("python高级阶段学习视频".center(30, "-"))
home()
first_stage()
second_stage()
third_stage()
View Code

  这种写法直接对源代码进行了修改,违反了“开放-封闭”原则。

  二、写法二

account = {
    "is_authenticated": False,  # 用户登录成功就把它改为True
    "username": "lilei",  # 数据库中的用户信息
    "pass_word": "123"  # 数据库中的用户密码
}

def login(func):
    if account["is_authenticated"]  == False:
        user_name = input("user:").strip()
        password = input("password:").strip()
        if user_name == account["username"] and password == account["pass_word"]:
            print("welcome login....")
            account["is_authenticated"] = True
        else:
            print("wrong username or password")
    if account["is_authenticated"] == True:
        func()

def home():
    print("python专区".center(30, "-"))
def first_stage():
    print("python初级阶段学习视频".center(30, "-"))
def second_stage():
    print("python中级阶段学习视频".center(30, "-"))
def third_stage():
    print("python高级阶段学习视频".center(30, "-"))
home()
first_stage()
login(second_stage)
login(third_stage)
View Code

  这种写法,虽然没有改变源代码,但改变了函数的调用方式。

  三、写法三

account = {
    "is_authenticated": False,  # 用户登录成功就把它改为True
    "username": "lilei",  # 数据库中的用户信息
    "pass_word": "123"  # 数据库中的用户密码
}

def login(func):
    def inner():  # 在内部再定义一层函数
        if account["is_authenticated"]  == False:
            user_name = input("user:").strip()
            password = input("password:").strip()
            if user_name == account["username"] and password == account["pass_word"]:
                print("welcome login....")
                account["is_authenticated"] = True
            else:
                print("wrong username or password")
        if account["is_authenticated"] == True:
            func()
    return inner  # 返回内部函数对象

def home():
    print("python专区".center(30, "-"))
def first_stage():
    print("python初级阶段学习视频".center(30, "-"))
def second_stage():
    print("python中级阶段学习视频".center(30, "-"))
def third_stage():
    print("python高级阶段学习视频".center(30, "-"))
home()
first_stage()
second_stage = login(second_stage)  # 至关于inner对象
third_stage = login(third_stage)  # 至关于inner对象
second_stage()  # 执行inner()
third_stage()  # 执行inner()
View Code

  这种写法就实现了既不改变源代码也不改变调用方式,但实现了功能的拓展,可是没法给second_stage() 或 third_stage()函数传参数。

  四、写法四

account = {
    "is_authenticated": False,  # 用户登录成功就把它改为True
    "username": "lilei",  # 数据库中的用户信息
    "pass_word": "123"  # 数据库中的用户密码
}

def login(func):
    def inner(*args, **kwargs):  # 在内部再定义一层函数
        if account["is_authenticated"]  == False:
            user_name = input("user:").strip()
            password = input("password:").strip()
            if user_name == account["username"] and password == account["pass_word"]:
                print("welcome login....")
                account["is_authenticated"] = True
            else:
                print("wrong username or password")
        if account["is_authenticated"] == True:
            func(*args, **kwargs)
    return inner  # 返回内部函数对象

def home():
    print("python专区".center(30, "-"))
def first_stage():
    print("python初级阶段学习视频".center(30, "-"))
def second_stage():
    print("python中级阶段学习视频".center(30, "-"))
def third_stage(vip_level):
    if vip_level > 3:
        print("python高级阶段学习视频".center(30, "-"))
    else:
        print("vip level is too lower")

home()
first_stage()
second_stage = login(second_stage)  # 至关于inner对象
third_stage = login(third_stage)  # 至关于inner对象
second_stage()  # 执行inner()
third_stage(1)  # 执行inner(1)
View Code

  这是装饰器的终极写法,既能够不改变源码实现对原有功能的扩展,还能够给函数传递参数。

相关文章
相关标签/搜索