上下文管理器
- 上下文管理的应用
- 常用于一些资源操作,需要在资源的获取与释放的时候做相关的操作
- 常见使用上下文管理的场景
- 打开/关闭文件
- 链接/关闭数据库
- 网站的访问
- 上下文管理器
- 什么是上下文管理器
- 实现了上下文协议的对象/函数即为上下文管理器
- 上下文协议
- 当我们需要创建一个上下文管理器类的时候,就需要实现__enter__和__exit__方法,这对方法就称为上下文管理协议(Context Manager Protocol),定义了一种运行时上下文环境。
- 自定义一个上下文管理器类对象
- 示例:
- class Contextor(object):
- def __enter__(self):
- pass
- def __exit__(self,*unused):
- pass
- 定义一个上下文管理器函数
- 实现方法
- 使用contextlib库来实现函数类型的上下文管理器
- 示例:
- @contextlib.contextmanager
- def func():
- handle = MongoClient('127.0.0.1', 27017)
- yield handle
- handle.close( )
- 创建方法
- 使用contextlib.contextmanager装饰上下文管理器函数
- 上下文管理器函数使用yield将代码段用到的对象返回
- 当上下文结束之后继续执行yield之后的工作
- 上下文管理器的使用方法
- with contextor [as var] :
- with_body
- 备注:
- contextor为上下文管理器,上下文管理器实现了上下文管理协议
- var变量存放上下文管理器返回的内容
- with_body为上下文过程中的处理代码
- with 关键字用于在代码块运行前进入上下文环境
- 当使用上下文管理器对象的时候,上下文管理器就创建好了
- 与with搭配使用上下文管理器会加载调用__enter__方法,如果有as var从句,则将__enter__结果赋值给var
- 代码块执行结束触发调用__exit__
- 代码块执行异常触发调用__exit__,如果有返回False,这样异常会再代码块位置再触发一遍,程序会报错。
- 常见的上下文管理器
- 类文件对象
- 创建数据库的句柄
- 线程的threading.Lock() 线程锁
- socket 创建的套接字对象
赋值、浅拷贝、深拷贝
- 赋值操作
- 赋值操作原理
- python中的赋值操作实际上就是引用的赋值与传递
- 示例:
- a = [11,22]
- b = a
- 示例解释:
- 实际上就是将[11, 22]在内存中的地址赋给了a, 因此a将会指向[11. 22],而b = a操作,则将a中存储的值赋给了b,所以a、被指向了同一个数据的引用
- 浅拷贝操作
- 浅拷贝操作的原理
- python中的浅拷贝使用copy模块的copy方法,拷贝时创建一个新的数据对象,并拷贝对象内部数据的引用
- 如果拷贝的数据本身就是个不可变类型数据(比如元组),那么就只拷贝其引用
- 示例:
- 常见的浅拷贝的场景
- 列表的切片
- 字典的copy方法
- list( )的内置函数
- 深拷贝操作
- 深拷贝操作的原理
- 创建一个新的数据对象,对每个包含的数据进行递归的拷贝操作,当检测到拷贝的引用指向的是一个不可修改的对象时,那么拷贝对象的引用
- 深拷贝是对数据对象的完全拷贝,当被拷贝的数据是可变类型将会复制其结构,深拷贝之后得到的结果与原数据没有任何的联系,任何对原数据的修改都不会影响深拷贝之后的数据
- 示例:
- 拷贝的特殊情况
- 拷贝元组数据
- 当元组中不含有可变类型数据的时候
- copy.copy和copy.deepcopy的到的结果都是对拷贝内容的引用
- eg: a = (11,22)
- 当元组中含有可变类型数据
- copy.copy拷贝的结果是引用
- copy.deepcopy是深拷贝
- eg: a = [11,22] b = [33,44]
- c = (a,b)
- 函数传参拷贝数据
- 函数传参的方法
- def func(*args, **kwargs)
- body
- 函数传参的时候需要注意
- 默认传参只是会传递引用
- 当参数为可变数据时(列表,字典等),如果参数只使用而不修改,可直接传参,如果涉及到修改,函数内的修改会影响函数外的使用
- 如果想避免第二种情况,可以传递深拷贝数据来避免函数修改原来数据