Python之闭包函数、装饰器

1、闭包函数

#作用域关系在函数定义阶段时就已经固定死了,与调用位置无关
# 即:在任意位置调用函数都需要跑到定义函数时寻找作用域关系

# def f1():
#     x=1
#     def inner():
#         print(x)   #闭包的含义:内部函数中的变量x引用外部作用域的x,而非全局作用域的x
#     return inner
# func=f1()          #f1()=inner
#
#
# def f2():
#     x=111111
#     func()        #func()=inner()
# f2()


# 闭包函数:
# 闭指的是:该函数是一个内部函数
# 包指的是:指的是该函数包含对外部作用域(非全局作用域)名字的引用
# def outter():
#     x = 1
#     def inner():
#         print(x)        #内部函数inner中的x是对外部作用域的引用,而非全局作用域的引用
#
#     return inner
#
# f=outter()
#
# def f2():
#     x=1111111
#     f()
#
# f2()
#
#
# def f3():
#     x=4444444444444
#     f()
#
# f3()


# 为函数传值的两种方式:
# 为函数体传值的方式一:使用参数的形式
# def inner(x):
#     print(x)
#
# inner(1)
# inner(1)
# inner(1)


# 为函数体传值的方式二:包给函数
'''
def outter(x):
    # x=1
    def inner():
        print(x)    #通过闭包函数将值报给内部函数
    return inner

f=outter(1)
f()
'''


# 例子:
# 方法一:通过传参的形式将值传给函数内的变量
# import requests
# def get(url):
#     response=requests.get(url)
#     if response.status_code == 200:
#         print(response.text)
#
# get('https://www.baidu.com')
# get('https://www.baidu.com')
# get('https://www.baidu.com')
#
# get('https://www.python.org')
# get('https://www.python.org')
# get('https://www.python.org')
# get('https://www.python.org')


# 方法二:通过闭包函数将值包给其内部的函数
import requests
def outter(url):                             #通过传参的形式,可以爬去任意网页的源代码
    # url='https://www.baidu.com'            #功能被写死,所以改成传参的形式
    def get():
        response=requests.get(url)           #url是通过outter函数,将值包给函数get内的函数体代码用的
        if response.status_code == 200:      #成立说明,成功爬去网页的源代码
            print(response.text)
    return get                               #返回get给外部的调用者,打破层级的限制(函数对象的知识)

baidu=outter('https://www.baidu.com')        #本质就是传入了参数的get的内存地址
python=outter('https://www.python.org')


baidu()                                      #本质就是已经给url传入了参数的get的内存地址,加括号即调用
baidu()

python()
python()

2、装饰器

'''
1、什么是装饰器
    器指的是工具,而程序中的函数就具备某一功能的工具
    装饰指的是为被装饰器对象添加额外功能

    就目前的知识来看:
        定义装饰器就是定义一个函数,只不过该函数的功能是用来为
        其他函数添加额外的功能

    其实:
        装饰器本身其实可以是任意可调用的对象
        被装饰的对象也可以是任意可调用的对象


2、为什么要用装饰器
    软件的维护应该遵循开放封闭原则
    开放封闭原则指的是:
        软件一旦上线运行后对修改源代码是封闭的,对扩展功能的是开放的
        这就用到了装饰器

    装饰器的实现必须遵循两大原则:
        1、不修改被装饰对象的源代码
        2、不修改被装饰对象的调用方式
    装饰器其实就在遵循1和2原则的前提下为被装饰对象添加新功能

3、如何用装饰器
'''


# 方式一
# 给原函数添加上了新功能,没有改变原函数的调用方式,但是却改变了源代码
import time
# def index():
#     start=time.time()
#     print('welcom to index')
#     time.sleep(3)
#     stop=time.time()
#     print('run time is %s' %(stop-start))
# index()

# 方法二
# 没有改变源代码,也没有改变调用方式,但是给不同函数扩展相同的功能时,是在重复写代码的过程
import time
# def index():
#     print('welcom to index')
#     time.sleep(3)
#
# def f2():
#     print('from f2')
#     time.sleep(2)

# 以下为两个函数添加上了引得功能,但是重复写代码
# start=time.time()
# index()
# stop=time.time()
# print('run time is %s' %(stop-start))
# #
# start=time.time()
# f2()
# stop=time.time()
# print('run time is %s' %(stop-start))


# 方法三
# 将重复写代码的过程,定义为一个函数的功能,虽然没有该源代码,但是改变了函数的调用方式
# import time
#
# def index():
#     print('welcom to index')
#     time.sleep(3)
#
# def timmer(func):
#     start=time.time()
#     func()
#     stop=time.time()
#     print('run time is %s' %(stop-start))
#
# timmer(index)

# 方法四
# 利用闭包函数,为函数添加上新的功能

'''
import time
def index():
    print('welcom to index')
    time.sleep(3)

def timmer(func): #func=最原始的index
    # func=index           #这样就把被装饰的对象写死了,所以需要以传参的形式将,被装饰的函数传进来
    def inner():
        start=time.time()
        func()
        stop=time.time()
        print('run time is %s' %(stop-start))
    return inner

# f=timmer(index)
# f()

# index=timmer(被装饰函数的内存地址)
index=timmer(index) #index=inner

index() #inner()


'''
import time

def index():
    print('welcom to index')
    time.sleep(3)

def timmer(func):        #将被装饰的函数传进来,不至于将被装饰的对象写死,固定是某一个,而是可以装饰任意一个函数
    #func=最原始的index ,即被装饰函数的的内存地址
    def wrapper():       #该函数即是为被装饰函数添加上的新功能
        start=time.time()
        func()           #最原始的index加括号即使调用最原始的函数
        stop=time.time()
        print('run time is %s' %(stop - start))
    return wrapper       #函数对象知识:返回给外部函数调用,打破层级限制

index=timmer(index)      #左边的index=wrapper函数的内存地址,右边的index即是我们要装饰的函数
index()                  #本质调用的是wrapper函数

三、装饰器修正

import time
def index():                                    #被装饰的函数无参,有返回值
    print('welcome to index')
    time.sleep(3)
    return 123

def home(name):                                #被装饰的函数有参,没有返回值
    print('welcome %s to home page' %name)
    time.sleep(2)


def timmer(func):
    #func=最原始的index
    def wrapper(*args,**kwargs):                #wrapper会将接收的参数,原封不动的传给被装饰的函数
        start=time.time()
        res=func(*args,**kwargs)                #因为被装饰的对象可能有的有参,有的是无惨,所以调用时用*args,**kwargs,无论有无参数都不会报错
        stop=time.time()
        print('run time is %s' %(stop - start))
        return res                              #接收被装饰函数的返回值,被装饰的函数没有返回值则为None,有则返回被装饰的返回值
    return wrapper                              #该返回值则是返回给外部函数用的,可以打破层级的限制,这样内部函数即给被装饰函数添加的新功能就可以被调用到


index=timmer(index)                             #将被装饰的函数传入,调用装饰器,本质就是调内部被加上新功能的函数
home=timmer(home)                               #将被装饰的函数传入,调用装饰器,本质就是调内部被加上新功能的函数

res=index()                                     #拿到调用函数的返回值,打印即可看到返回值
home('egon')                                    #被装饰的函数为有参,为被装饰函数进行传参
print(res)

#装饰器语法糖
# 在被装饰对象正上方,并且是单独一行写上@装饰器名
# import time
# def timmer(func):
#     #func=最原始的index
#     def wrapper(*args,**kwargs):
#         start=time.time()
#         res=func(*args,**kwargs)
#         stop=time.time()
#         print('run time is %s' %(stop - start))
#         return res
#     return wrapper
#
# @timmer # index=timmer(index)   #timmer即一个名字,所以装饰器的代码块要写在timmer的上方,@timmer本质就是调用了timmer(传入被装饰的函数名)
# def index():
#     print('welcome to index')
#     time.sleep(3)
#     return 123
#
# @timmer # home=timmer(home)
# def home(name):
#     print('welcome %s to home page' %name)
#     time.sleep(2)
#
# res=index()
# home('egon')


# 装饰器的万能模板:
def deco(func):                   #func即是要接收的被砖石的函数名
    def wrapper(*args,**kwargs):  #可以根据被装饰的函数需不需要传参,给被装饰的对象传入参数
        res=func(*args,**kwargs)  #本质就是调用被装饰的函数, 接收传进来的参数
        return res                #接收被装饰函数的返回值,没有则返回None
    return wrapper                #外部函数将内部函数的内存地址返回,打破层级限制

猜你喜欢

转载自www.cnblogs.com/sui776265233/p/9168920.html