Python中函数的闭包和装饰器

1. python的内部函数示例

python 复制代码
# 定义一个外部函数
def func_out(num1):
    # 定义一个内部函数
    def func_inner(num2):
        # 内部函数使用了外部函数的变量(num1)
        result = num1 + num2
        print("结果是:", result)
    # 外部函数返回了内部函数,这里返回的内部函数就是闭包
    return func_inner

# 创建闭包实例,返回内部函数    
# 此时的f是内部函数
f = func_out(100)
# 执行闭包
f(2)
f(3)

"""
f接收到func_out的返回值
f = func_inner
f() = func_inner()
"""

示例2:

python 复制代码
def config_name(name):
    def say_hello(info):
        print(f"{name}: {info}")
    return say_hello


if __name__ == '__main__':
    # 创建闭包实例
    tom = config_name("tom")
    tom("What did you have for lunch ?")

    jarry = config_name("jarry")
    jarry("I had vegetables and beef.")

"""
tom: What did you have for lunch ?
jarry: I had vegetables and beef.
"""

调用闭包相当于调用内部函数

python 复制代码
闭包的构成条件
1. 在函数嵌套的前提下
2. 内部函数使用了外部函数的变量(还包括外部函数的参数)
3. 外部函数返回了内部函数

结论:闭包可以对外部函数的变量进行保存

2. 闭包内修改外部变量

python 复制代码
def func_out(num1):
    def func_inner(num2):
        # 此时的num1属于内部函数,不是外部函数的num1
        num1 = num2 + 100

    print("改前:num1 =",num1)
    # 调用内部函数修改num1的值
    func_inner(200) # 调用方法改变num1的值
    print("改后:num1 =",num1)
    return func_inner
# 实例化闭包
f = func_out(10)

"""
改前:num1 = 10
改后:num1 = 10
"""
python 复制代码
def func_out(num1):
    def func_inner(num2):
        # 此时的num1是外部函数变量
        nonlocal num1
        num1 = num2 + 100

    print("改前:num1 =",num1)
    # 调用内部函数修改num1的值
    func_inner(200) # 调用方法改变num1的值
    print("改后:num1 =",num1)
    return func_inner
# 实例化闭包
f = func_out(10)
# f(10) --> 这是调用闭包(内部函数),这里没有调用闭包,只是创建了闭包
"""
改前:num1 = 10
改后:num1 = 300
"""

修改闭包使用的外部函数变量使用nonlocal关键字修饰

3. 装饰器:在不改变原有函数的源代码的情况下,给函数添加功能

python 复制代码
1.不修改原有函数的源代码
2. 给已有的函数添加额外的功能

符合开发中的封闭开放原则
python 复制代码
# 1. 定义一个装饰器(一个闭包, 一个内部函数)
def check(fn):
    # fn是comment函数
    def inner():
        print("请先登录")
        fn()
    return inner
# 2. 需要被装饰的函数
def comment():
    print("发表评论")

# 3. 使用装饰器装饰函数(增加一个登录功能)
# 左侧的comment函数已经变成了inner()函数
comment = check(comment)
comment()
"""
请先登录
发表评论
"""

装饰器就是把一个函数当作参数传递给闭包中的外部函数,同时在内部函数中使用这个函数,并给它添加新的功能

python 复制代码
def check(fn):
    def inner():
        print("请先登录")
        fn()
    return inner

# 解释器遇到@check,会执行comment = check(comment)
@check
def comment():
    print("发表评论")

comment()
"""
请先登录
发表评论
"""

4.修饰带参数的函数

python 复制代码
"""装饰带参数的函数"""
def loggin(fn):
    def inner(a,b):
        print("请先登录")
        fn(a,b)
    return inner

def sum_num(a,b):
    result = a+b
    print(result)


# sum_num = inner
sum_num = loggin(sum_num)
sum_num(1,2)
"""
请先登录
3
"""
python 复制代码
"""装饰带参数的函数"""
def loggin(fn):
    def inner(a,b):
        print("请先登录")
        fn(a,b)
    return inner

# sum_num = inner, sum_sum = loggin(sum_num)
@loggin
def sum_num(a,b):
    result = a + b
    print(result)

sum_num(1,2)
"""
请先登录
3
"""

5. 装饰带有返回值的函数

python 复制代码
"""装饰带返回值的函数"""
def loggin(fn):
    def inner(a,b):
        print("请先登录")
        return fn(a,b)
    return inner

@loggin
def sum_num(a,b):
    result = a+b
    return result

ans = sum_num(1,2)
print("ans = ",ans)
"""
请先登录
ans =  3
"""

6. 修饰不定长参数的函数

python 复制代码
def loggin(fn):
    def inner(*args):
        print("请先登录")
        return fn(*args)
    return inner

@loggin
def sum_args(*args):
    ans = sum(args)
    return ans

ans = sum_args(1,2,3,4,5)
print("ans = ",ans)
"""
请先登录
ans =  15
"""

7. 多个装饰器的使用

python 复制代码
def check1(fn):
    def inner1():
        print("登录验证1")
        fn()
    return inner1

def check2(fn):
    def inner2():
        print("登录验证2")
        fn()
    return inner2

@check2
@check1
def comment():
    print("发表评论")

comment()
"""
登录验证2
登录验证1
发表评论
"""

8. 带有参数的装饰器

python 复制代码
"""
带参数的装饰器,正确案例
"""
def loggin(flag):
    def decorator(fn):
        def inner(num1, num2):
            # 判断流程
            if flag == "+":
                print("--正在努力加法计算--")
            elif flag == "-":
                print("--正在努力减法计算--")
            ant = fn (num1,num2)
            return ant
        return inner
    return decorator

# 被带有参数的装饰器饰的函数
@loggin("+")  # 1. loggin("+")  2. @decorator起到装饰器的功能了
def sum_num(a, b):
    res = a + b
    return res

result = sum_num(1,3)
print("result = ",result)
python 复制代码
带参数的装饰器
1. 装饰器的外部函数只接受一个参数 -- 被装饰的函数
2. 需要给装饰器参数需要在装饰器外部再增加一个函数

9. call方法

python 复制代码
class Check(object):
    def __call__(self,*args,**kwargs):
        print("请先登录")

c1 = Check()
c1()
"""请先登录"""

10. 类装饰器

python 复制代码
class Check(object):
    def __init__(self,fn):
        self._fn = fn
    def __call__(self,*args,**kwargs):
        print("请先登录")
        self._fn()

@Check   # comment = Check(comment)
def comment():
    print("发表评论")

comment()
"""
请先登录
发表评论
"""

11. property 装饰器方式

python 复制代码
class Person(object):
    def __init__(self) -> None:
        self.__age = 0
    
    @property
    def age(self):
        return self.__age
    
    @age.setter
    def age(self, new_age):
        self.__age = new_age


p = Person()
print(p.age)

p.age = 100
print(p.age)

12. property类属性方式

python 复制代码
class Person(object) : 
    def __init__(self) -> None:
        self.__age = 0
    
    def get_age(self):
        return self.__age
    
    def set_age(self, new_age):
        if new_age >= 150:
            print("年龄错误")
        else:
            self.__age = new_age
    
    age = property(get_age, set_age)


p = Person()
print(p.age)

p.age = 60
print( p.age )
相关推荐
用户0595401744630 分钟前
LLM对话记忆测试踩坑实录:手工回归30分钟,自动化后2分钟发现3个隐藏Bug
前端·css
Draina1 小时前
CBC填充预言攻击-CBC Padding Oracle Crypto Attack
python·安全·web安全·网络安全·密码学·安全性测试
MonolithIoT1 小时前
实战方案|设备备件无人值守仓库:连续化产线运维备件 7×24 小时数字化管控方案
运维·网络·数据库
Angel Q.1 小时前
特征提取 | DINO 到 DINOv3
图像处理·python
瞬间&永恒~2 小时前
【MySQL】4-6:在同一个主机上使用 systemd 运行多个 MySQL服务器
服务器·数据库·mysql
Ashley的成长之路2 小时前
前端性能优化实战手册·第2篇:资源加载策略全解
前端·性能优化·资源加载·http/3·性能优化实战·资源加载优化
浅水壁虎2 小时前
vue基础(第二章 )
前端·javascript·vue.js
不如语冰2 小时前
AI大模型入门-pytorch-张量2 tensor创建
python
界面开发小八哥2 小时前
界面控件DevExtreme v26.1新版亮点——支持Angular 22
前端·javascript·angular.js·devexpress·ui开发·devextreme