python之闭包,装饰器

目录

函数对象 :相当于变量名

函数对象的作用:

1. 可以引用

def f1():
    print("from f1")

a = f1
a()

'''
from f1

'''

2. 可以作为函数的返回值

def f1():
    print("from f1")

def f2():
    return f1

a = f2()
a()

'''
from  f1
'''

3. 可以作为容器的元素

def f1():
    print("from f1")
a = [1,2,3,4,5,f1]

4. 可以作为函数的参数

def f1():
    print("from f1")

def f2(func):
    func()

f2(f1)

'''
from f1
'''

闭包

定义:

如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内部的我们叫他内函数。那闭包就是,在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包

ps:

一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给内部函数,然后自己结束。

闭包的意义:

返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得该函数无论在何处调用,优先使用自己外层包裹的作用域

# 闭包
def test_plf(x):
    def test_lt():
        print(x)
    return test_lt

f1 = test_plf(8)
f1()


# 闭包的应用
import requests
def req(url):
    def test_plf():
        request = requests.get(url)
        data = request.status_code
        print(data)
    return test_plf

baidu = req("https://www.baidu.com")
baidu()
baidu()
baidu()
boke = req("https://www.cnblogs.com/plf-Jack/")
boke()
boke()
boke()


# 使用普通函数进行对比
import requests
def req(url):
    content = requests.get(url)
    data = content.status_code
    print(data)

req("https://www.baidu.com")
req("https://www.baidu.com")
req("https://www.baidu.com")
req("https://www.cnblogs.com/plf-Jack/")
req("https://www.cnblogs.com/plf-Jack/")
req("https://www.cnblogs.com/plf-Jack/")

'''
	总结:
		相比使用普通函数和使用闭包函数实现相同业务逻辑
		1. 闭包在调用上要比普通函数要简单
		2. 闭包相对于普通函数的定义,逻辑上难度要大一些
		3. 闭包主要应用于延迟计算,爬虫领域
'''

装饰器

本质:装饰器 = 函数。它的本质就是函数

作用:给原函数增加新的功能

原则:

1. 不能改变被装饰的函数的调用方式

2. 装饰器不能修改装饰函数的源代码

实现装饰器的知识储备:

1. 函数即“变量”

2. 高阶函数。即一个函数可以作为另外一个函数的参数,这种函数就称之为高阶函数。

3. 嵌套函数。即定义一个函数时,在其函数体中又定义了一个函数,这个函数称之为嵌套函数。

装饰器的模板语法

def deco(func):
    def wrapper(*args,**kwargs):
        res = func(*args,**kwargs)
        return res
    return wrapper
  1. 无参装饰器

    import time
    def test_lt(func):
        def warpper():
            start_time = time.time()
            func()
            end_time = time.time()
            print("你睡了%s秒"%(end_time-start_time))
        return warpper
    
    @test_lt   # 语法糖,即简洁。它等同于 test_plf = test_lt(test_plf)
    def test_plf():
        time.sleep(1)
        print("我睡了多长时间")
    
  2. 返回值装饰器

    import time
    
    def test_lt(func):
        def warpper():
            start_time = time.time()
            res = func()
            end_time = time.time()
            print("睡了%s秒"%(end_time-start_time))
            return res
        return warpper
    
    @test_lt  #test_plf = test_lt(test_plf)
    def test_plf():
        time.sleep(1)
        print("我睡了多长时间")
        return 123
    
    a = test_plf()
    print("返回值为%d"%a)
    
  3. 有参装饰器

    dic = {"PLF":'123'}
    is_login = False
    def auth(test_type='file'):
        def login_desc(func):
            def wrepper():
                if test_type == "file":
                    global is_login			# 声明的是全局变量的is_login
                    if not is_login:
                        user_name = input("请输入账号>>>")
                        user_pwd = input("请输入密码>>>")
                        if dic.get(user_name) != user_pwd:
                            print("输入错误")
                            return
                        print("密码输入正确")
                        is_login = True
                        func()
                        return
                    func()
                elif test_type == "txt":
                    print("文件类型不正确")
                else:
                    print("你走开")
            return wrepper
        return login_desc
    
    
    @auth(test_type="file")
    def go_shopping():
        print("购物")
    
    @auth(test_type="txt")
    def pay():
        print("支付")
    
    @auth(test_type="makeDown")
    def see_list():
        print("查看清单")
    
    go_shopping()
    pay()
    see_list()
    

装饰器的弊端:

import time

def test_lt(func):
    def warpper():
        start_time = time.time()
        res = func()
        end_time = time.time()
        print("睡了%s秒"%(end_time-start_time))
        return res
    return warpper

@test_lt  #test_plf = test_lt(test_plf)
def test_plf():
    time.sleep(1)
    print("我睡了多长时间")
    return 123

print(test_plf.__name__)


'''
warpper
'''


'''
	总结:
		1. 目标函数(test_plf)是一个函数对象,它里米那有自己的属性,如函数名__name__,说明文档__doc__等等。但如果目标函数被装饰器装饰之后,我们在调用目标函数的__name__会发现,本来我们想要的test_plf名字,结果打印出来了warpper。这种情况确实不出乎意料,因为test_plf被装饰之后确实存的就是warpper了,我们对test_plf的操作实际上都是对inner的操作.
		2. 以上的操作带来了使用的不一致性。如果我们能把本来目标函数各种方法覆盖给test_plf函数就好了。这里我们可以用functools包里的工具来实现。这里暂不做解释,有兴趣的同学先去百度一下。
'''

参考博客:https://www.cnblogs.com/Lin-Yi/p/7306235.html

原文地址:https://www.cnblogs.com/plf-Jack/p/10957486.html