当前位置 : 主页 > 编程语言 > python >

python中with的用法

来源:互联网 收集:自由互联 发布时间:2022-06-15
一、文件操作 #自行车 f=open("filename") f.write() f.close() 上述代码存在的问题: (1)直接open()打开需要手动关闭,并且容易忘记关闭 (2)当文件操作出现异常导致程序提早离开,而没有执

一、文件操作

#自行车

f=open("filename")
f.write()
f.close()

上述代码存在的问题:

(1)直接open()打开需要手动关闭,并且容易忘记关闭

(2)当文件操作出现异常导致程序提早离开,而没有执行关闭文件操作

#小轿车

try:
f=open("xxx")
f.write() #文件操作
except:
do something
finally:
f.close()

虽然功能完善了,但是代码这么冗余,也太笨了吧

#特斯拉

with open("xxx") as f:
f.write() #文件操作

一个with代码块直接解决一切,无论怎样的方式退出代码块都会自动关闭文件

问题来了,

with为什么可以做到自动关闭文件?
with为什么即便文件操作中出现异常也可以正常关闭文件?with语句和原始open同样返回一对象,有什么不一样?

二、with原理

__enter__()方法:紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。

__exit__()方法:当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法

class Test(object):
def __enter__(self):
print("执行了 __enter__方法")
return "enter返回的内容"

def __exit__(self, type, value, trace):
print("执行了 __exit__方法")

with Test() as test:
print("test:", test)

运行结果:

执行了 __enter__方法
test: enter返回的内容
执行了 __exit__方法

执行过程:

with后面的Test()语句执行、enter()执行
enter()返回值返回给as后面的变量test
执行with语句中间代码块打印变量test、
中间代码块执行完后执行__exit__()
推断:自动关闭文件是在__exit__()中调用文件关闭方法

三、实现支持with的类

open支持with语法,就是因为内部实现了双下enter和双下exit

想让类来使用with就必须支持with语法,即内部实现双下enter和双下exit,如下:

import sys
import time
import threading
class Spinner:
busy = False
delay = 0.5

@staticmethod
def spinning_cursor():
while 1:
for cursor in '|/-\\':
yield cursor

def __init__(self, delay=None):
print(111)
self.spinner_generator = self.spinning_cursor()
if delay and float(delay):
self.delay = delay

def spinner_task(self):
while self.busy:
print(333)
sys.stdout.write(next(self.spinner_generator)) #IO
print(999)
sys.stdout.flush()
time.sleep(self.delay) #IO
print(666)
sys.stdout.write('\b')
sys.stdout.flush()
print(777)

def __enter__(self):
print(222)
self.busy = True
threading.Thread(target=self.spinner_task).start()

def __exit__(self, exception, value, tb):
self.busy = False
time.sleep(self.delay)
if exception is not None:
return False
with Spinner():
print(444)
t1 = time.time()
while time.time()-t1 < 2:
print(555)
time.sleep(1) #io
print('完蛋了')

python中with的用法_文件操作python中with的用法_赋值_02

111 # 执行__init__
222 # 执行__enter__
333 # 执行任务spinner_task线程1
444|999 # 遇到write的io,执行另外的线程2,线程1的io完毕,立即切换回去继续执行线程1输出‘|’

555 # 线程1遇到sleep的io立即切换线程2,走到sleep又io,切换回线程1
666
777
333
/999
完蛋了
555
666
777
333
-999
666
777
333
\999
完蛋了 # 时间大于2,线程2的while执行完毕,即with代码块执行完毕,开始执行__exit__,设置退出标志
666
777 # 线程1输出完毕,while遇到退出信号也完毕了,大家都完了

结果分析

 

 


网友评论