python高阶--闭包、装饰器、深浅拷贝

欢迎观看,欢迎指正,共同学习

1、闭包

目的:延长外部函数的变量的生命周期
构成条件:
	1、有嵌套:外部函数里套一个内部函数
	2、有引用:内部函数里引用了外部函数的变量
	3、有返回:外部函数返回了内部函数名(本质是返回了地址)
格式:
	def 外部函数名(a):
		def 内部函数名():
			引用外部函数变量a
			(根据需求return)
		return 内部函数名
注意:函数名本质记录的地址
函数引用传递
isinstance():用于判断一个对象是否是一个已知的类型
global: 声明全局变量
nonlocal: 用于声明要修改的是外层函数的局部变量

1.1、闭包入门

# 先定义函数
def outer():
    a = 10
    def inner():
        nonlocal a
        a = 20
        print(f'修改的结果:{a}')
    return inner
# 再调用函数
f = outer()
f()

2、装饰器

作用:在不改变原有函数定义和调用的基础上,给原有函数添加额外功能
构成条件:
	1、有嵌套
	2、有引用
	3、有返回
	4、有额外功能
写法:
	方式1:原生调用语法
		变量名 = 装饰器名(原有函数名)
			变量名()
	方式2:语法糖语法:快捷方式(类似三目运算符,列表推导式)
		@装饰器名
注意:同时使用两种方式,会调用两次内部函数
可变参数:
	*args:*把所有的位置传参进来的参数放到args元组中
	**kwargs:**把所有的关键字传参的参数放到了kwargs字典中
	注意:*和**还可以在传参的时候把列表和字典进行自动拆包的操作
	*把列表中元素一个个取出,**把字典中的键值对一个个取出作为参数传递

2.1、装饰器原生调用方式

#1、先定义原有函数
def comment():
    print('----发表评论功能开始-----')
    print('此处省略很多代码')
    print('---发表评论功能结束---')
def outer(func):
    """
    定义一个装饰器函数,用于扩展其他函数的功能。
    :param func: 被装饰的函数。
    :return: 返回一个闭包函数,用于在执行被装饰函数前添加额外功能。
    """
    def inner():
        """
        闭包函数,用于在被装饰函数执行前添加额外的逻辑。
        """
        print('新增验证用户是否登录的功能')
        func()
    return inner
# 使用装饰器对comment函数进行装饰,以增加验证用户是否登录的功能
comment = outer(comment)
# 调用装饰后的comment函数
comment()

2.2、装饰器语法糖方式

# 3、定义装饰器
# 有嵌套
def outer(func):#TODO 注意:此处func用于接收原有函数
    def inner():
        # 有额外功能
        print('新增验证用户是否登录的功能')
        # 有引用
        func()#TODO 注意:此处func()就是调用原有函数
    # 又返回
    return inner
@outer
def comment():
    print('----发表评论功能开始-----')
    print('此处省略很多代码')
    print('---发表评论功能结束---')
# comment = outer(comment)----->同时使用两种方式,会打印两次
comment()

2.3、装饰器装饰可变参数的函数

def outer(func):
    def inner(*args,**kwargs):
        he = func(*args,**kwargs)
        return he
    return inner
def get_num(*args,**kwargs):
    print(args)
    print(kwargs)
    sum = 0
    for i in args:
        sum += i
    for i in kwargs.values():
        sum += i
    return sum
he = get_num(1,2,3,a=4,b=5)
print(he)

2.4、多个装饰器装饰一个函数

def check_user_info(func):
    def inner():
        print('新增校验用户名好饿密码的功能')
        func()
    return inner
def check_code(func):
    def inner():
        print('新增校验验证码的功能')
        func()
    return inner
@check_code
@check_user_info
def comment():
    print('原有发表评论功能...')
comment()

2.5、带参数的装饰器

2.5.1、传统方式
#语法糖方式只能接受一个参数,只能用传统方式
def outer(func,flag):
    def inner(a,b):
        if flag == "+":
            print('正在做加法运算中...')
        elif flag == "-":
            print('正在做减法运算中.....')
        func(a,b)
    return inner
def get_sum(a,b):
    sum = a + b
    print(sum)
def get_diff(a,b):
    diff = a - b
    print(diff)

if __name__ == '__main__':
    get_sum = outer(get_sum,"+")
    get_diff = outer(get_diff,"+")
    get_sum(2,1)
    print('-------')
    get_diff(2,1)
2.5.2、语法糖方式
def parameter(flag):
    def outer(func):
        def inner(a,b):
            if flag == "+":
                print('正在做加法运算中...')
            elif flag == "-":
                print('正在做减法运算中.....')
            func(a,b)
        return inner
    return outer
@parameter("+")
def get_sum(a,b):
    sum = a + b
    print(sum)
@parameter("-")
def get_diff(a,b):
    diff = a - b
    print(diff)

if __name__ == '__main__':
    get_sum(2,1)
    print('-------')
    get_diff(2,1)

3、深浅拷贝

不可变类型:都没有开辟新空间,都只是引用地址传递
可变类型:直接赋值字面量就是开辟了新的空间,但是变量传递的还是引用地址
拷贝:
拷贝成功:开辟了新的空间 --(拷贝后内容没有影响)

浅拷贝
定义:
	创建新对象,其内容是原对象的引用
	浅拷贝仅仅只拷贝了一层,拷贝了最外围的对象本身
深拷贝
定义:
	拷贝对象及其所包含的所有子对象的独立副本。新对象与原对象完全独立,修改新对象不会影响原对象。

不可变类型深拷贝:不可变类型进行深拷贝不会给拷贝的对象开辟新的内存空间,而只是拷贝了这个对象的引用

深浅拷贝的相同点:
对于不可变类型:都没有开辟新的空间,都只是引用地址传递
对于可变类型只有1层时:都开辟了新的空间,都能拷贝成功
不同点:
对于第2层及以上,只有深拷贝才能开辟新空间,浅拷贝就变成了引用传递

3.1、仅1层示例:

# 导包
from copy import copy
from copy import deepcopy

# 不可变类型: 整数,浮点数,字符串,元组
# 整数
a1 = 10
b1 = copy(a1)
c1 = deepcopy(a1)
print(a1, b1, c1)
print(id(a1), id(b1), id(c1))
print('-----------------------------------------------')
# 浮点数
a2 = 3.14
b2 = copy(a2)
c2 = deepcopy(a2)
print(a2, b2, c2)
print(id(a2), id(b2), id(c2))
print('-----------------------------------------------')
# 字符串
a3 = "你好"
b3 = copy(a3)
c3 = deepcopy(a3)
print(a3, b3, c3)
print(id(a3), id(b3), id(c3))
print('-----------------------------------------------')
# 元组
a4 = (1, 2, 3)
b4 = copy(a4)
c4 = deepcopy(a4)
print(a4, b4, c4)
print(id(a4), id(b4), id(c4))
print('============================================================')
# 可变类型: 列表,集合,字典
# 列表
a5 = [1, 2, 3]
b5 = copy(a5)
c5 = deepcopy(a5)
print(a5, b5, c5)
print(id(a5), id(b5), id(c5))
print('-----------------------------------------------')
# 集合
a6 = {1, 2, 3}
b6 = copy(a6)
c6 = deepcopy(a6)
print(a6, b6, c6)
print(id(a6), id(b6), id(c6))
print('-----------------------------------------------')
# 字典
a7 = {1: 'a', 2: 'a', 3: 'a'}
b7 = copy(a7)
c7 = deepcopy(a7)
print(a7, b7, c7)
print(id(a7), id(b7), id(c7))

3.2、两层即以上嵌套示例:

# 导包
from copy import copy
from copy import deepcopy
# 以下以列表为例,其他的可变类型同理
# 定义列表a,嵌套多层,然后分别做深浅拷贝,修改内容观察效果
a = [10, 20, [30, 40, ['张三', '王五']]]
b = copy(a)
c = deepcopy(a)
# TODO 深浅拷贝相同点:对于第1层都开辟了新空间,原有内容变化,都不会受影响
print(a, b, c)
print(id(a), id(b), id(c))
# 修改原有第一层内容,深浅拷贝的结果都不会受影响
a[0] = 11
print(a, b, c)
print(id(a), id(b), id(c))
print('===================================================================')
# TODO 深浅拷贝不同点: 对于第2层及以上,只有深拷贝才能开辟新空间,浅拷贝就变成了引用传递
# 第二层
print(a[2], b[2], c[2])
print(id(a[2]), id(b[2]), id(c[2]))
# 修改第二层内容,浅拷贝结果会受影响,而深拷贝不会受影响
a[2][0] = 33
print(a[2], b[2], c[2])
print(id(a[2]), id(b[2]), id(c[2]))
print('------------------------------------------')
# 第三层
print(a[2][2], b[2][2], c[2][2])
print(id(a[2][2]), id(b[2][2]), id(c[2][2]))
# 修改第三层内容,浅拷贝结果会受影响,而深拷贝不会受影响
a[2][2][0] = '李四'
print(a[2][2], b[2][2], c[2][2])
print(id(a[2][2]), id(b[2][2]), id(c[2][2]))

你可能感兴趣的:(python,闭包,装饰器,python)