Python-闭包和修饰器

作用域

# 作用域:名字起作用的范围
# 作用:解决同名字可以共存问题 - 不同作用域相同名字的值都能在其作用域范围下进行使用
'''
四种作用域: LEGB
Built-in:内置作用域 - 所有文件所有地方都可以被访问
Global:全局作用域 - 在当前文件的所有位置
Enclosing:嵌套作用域 - 自身内部与内部的子函数
Local:局部作用域 - 只有自身内部
'''
# 加载顺序:Built-in > Global > Enclosing > Local
# 访问(查找)顺序:报错 < Built-in < Global < Enclosing < Local
# 作用范围:Built-in > Global > Enclosing > Local

闭包

# 闭包:定义在函数内部的函数,这个内部的函数就是闭包

# 应用场景:
# 1.可以去使用其他函数的内部变量,且还可以保证调用位置不变(闭包的函数对象作为那个函数的返回值)
def outer():
    count = 3000
    def fn():
        print(count)  # 能使用outer内部的变量count
    return fn
# 还是在外界调用
outer()()  # outer()() => fn() => 调用fn


# 2.延迟执行(外层函数可以为内存函数传递参数)
import requests
def outer(url):
    def show_html():
        response = requests.get(url)
        print(response.text)
    return show_html

# 制作 爬百度与新浪的 函数对象
show_baidu = outer('https://www.baidu.com')
show_sina = outer('https://www.sina.com.cn')

# 延迟到需求来了,需要爬百度,就用百度函数对象,需要爬新浪,就用新浪函数对象
show_baidu()
show_sina()
show_baidu()
code:
# closure:闭包
# 闭包:定义在函数内部的函数,这个内部的函数就是闭包

# 应用场景:
# 1.可以去使用其他函数的内部变量,且还可以保证调用位置不变(闭包的函数对象作为那个函数的返回值)
def outer():
    count = 3000
    def fn():
        print(count)  # 能使用outer内部的变量count
    return fn
# 还是在外界调用
outer()()  # outer()() => fn() => 调用fn

# 2.延迟执行(外层函数可以为内存函数传递参数)
import requests

# def show_html(url):
#     response = requests.get(url)
#     print(response.text)
#
# show_html('https://www.baidu.com')
# show_html('https://www.baidu.com')
# show_html('https://www.sina.com.cn')

def outer(url):
    def show_html():
        response = requests.get(url)
        print(response.text)
    return show_html
# 制作 爬百度与新浪的 函数对象
show_baidu = outer('https://www.baidu.com')
show_sina = outer('https://www.sina.com.cn')
# 延迟到需求来了,需要爬百度,就用百度函数对象,需要爬新浪,就用新浪函数对象
show_baidu()
show_sina()
show_baidu()

装饰器

# 装饰器:装饰器就是闭包的一个应用场景
#       -- 外层函数与内存函数形成的闭包结构的一种综合使用

# 重点:开放封闭原则
# 开放:拓展功能的点是开放的 - 可以为之前的函数添加新功能
# 封闭:1.不能改变原函数的源代码  2.还有通过原函数的函数对象来调用函数

def huaping():
    print('插花功能')

temp = huaping
def my_huaping():
    temp()
    print('观赏功能')
huaping = my_huaping

huaping()

# ----------------------------------------

def huaping():
    print('插花功能')

def outer(temp):  # temp = huaping
    def my_huaping():
        temp()
        print('观赏功能')
    return my_huaping
huaping = outer(huaping)  # huaping = my_huaping

huaping()


# ----------------------------------------------
def outer(temp):  # temp = huaping
    def my_huaping():
        temp()
        print('观赏功能')
    return my_huaping

@outer  # huaping = outer(huaping)
def huaping():
    print('插花功能')
    
huaping()


# ------------------------------------------
# 被装饰的函数可能有参有返:装饰器模板,可以满足所有参数,且能装饰原函数返回值
def outer(func):  # temp = huaping
    def inner(*args, **kwargs):
        pass
        res = func(*args, **kwargs)
        pass
        return res
    return inner

@outer
def any_method():
    pass

code:
# 装饰器:装饰器就是闭包的一个应用场景
#       -- 外层函数与内存函数形成的闭包结构的一种综合使用


# def huaping():
#     print('插花功能')

# 需求:如何拓展一个原有函数的功能
#       -- 修改源代码
#       -- 创建一个包含该功能和其他新功能的新函数

# 开放封闭原则:
# 开放:拓展功能的点是开放的 - 可以为之前的函数添加新功能
# 封闭:1.不能改变原函数的源代码  2.还有通过原函数的函数对象来调用函数

# 错误一:修改了源代码
# def huaping():
#     print('插花功能')
#     print('观赏功能')
# huaping()

# 错误二:改变了调用方式
# def huaping():
#     print('插花功能')
# def my_huaping(fn):
#     fn()
#     print('观赏功能')
# my_huaping(huaping)

# 装饰器:满足开放封闭原则还能拓展新功能,简单
'''
def huaping():
    print('插花功能')

temp = huaping
# temp = '呵呵'
def my_huaping():
    temp()
    print('观赏功能')
huaping = my_huaping

huaping()
'''

# 装饰器演变一:
'''
def huaping():
    print('插花功能')

def outer(fn):  # fn = huaping
    # temp = huaping  # 可以提取到实参对形参传递
    def my_huaping():
        fn()
        print('观赏功能')
    return my_huaping
huaping = outer(huaping)  # 要整合该条逻辑

huaping()
'''

# 装饰器演变二:
def outer(fn):  # fn = 原功能的huaping
    def my_huaping():  # my_huaping => 新功能的huaping
        fn()
        print('观赏功能')
    return my_huaping

@outer  # huaping = outer(huaping)  被装饰的函数对象 = 装饰器外层函数对象(被装饰的函数对象)
def huaping():
    print('插花功能')

huaping()  # 被装饰后的my_huaping

装饰器案例

# 为登录功能添加账号检验功能:必须是3个及以上英文字母组成
def check_user(func):
    def inner(user, pwd):
        if not (user.isalpha() and len(user) >= 3):
            return '账号不合法'
        res = func(user, pwd)
        return res
    return inner

# 为登录功能添加密码检验功能:必须是3个及以上英文字母或数字组成
def check_pwd(func):
    def inner(*args, **kwargs):
        pwd = args[1]
        if not (pwd.isalnum() and len(pwd) >= 3):
            return '密码不合法'
        res = func(*args, **kwargs)
        return res
    return inner

# 对登录结果的修饰装饰器:True=>登录成功 False=>登录失败
def change_res(func):
    def inner(*args, **kwargs):
        res = func(*args, **kwargs)
        if res == True:
            return '登录成功'
        return '登录失败'
    return inner


# 装饰器被执行的过程是从上至下
@check_user  # login = check_user(func=login) = inner
@check_pwd
@change_res
def login(user, pwd):  # 被装饰的函数对象
    if user == 'owen' and pwd == '123':
        return True
    return False

user = input('user: ')
pwd = input('pwd: ')
res = login(user, pwd)

print(res)

code:

# 为登录功能添加账号检验功能:必须是3个及以上英文字母组成
def check_user(func):
    def inner(user, pwd):
        if not (user.isalpha() and len(user) >= 3):
            return '账号不合法'
        res = func(user, pwd)
        return res
    return inner

# 为登录功能添加密码检验功能:必须是3个及以上英文字母或数字组成
def check_pwd(func):
    def inner(*args, **kwargs):
        pwd = args[1]
        if not (pwd.isalnum() and len(pwd) >= 3):
            return '密码不合法'
        res = func(*args, **kwargs)
        return res
    return inner

# 对登录结果的修饰装饰器:True=>登录成功 False=>登录失败
def change_res(func):
    def inner(*args, **kwargs):
        res = func(*args, **kwargs)
        if res == True:
            return '登录成功'
        return '登录失败'
    return inner


@check_user  # login = check_user(func=login) = inner
@check_pwd
@change_res
def login(user, pwd):
    if user == 'owen' and pwd == '123':
        return True
    return False

user = input('user: ')
pwd = input('pwd: ')
res = login(user, pwd)

print(res)



# 装饰器:固定写法
def outer(func):
    def inner(*args, **kwargs):
        pass
        res = func(*args, **kwargs)
        pass
        return res
    return inner

@outer
def f1():  # 任意函数
    pass
f1()



你可能感兴趣的:(Python-闭包和修饰器)