Python with 语句详解
本帖最后由 qiuyouzhi 于 2020-6-7 07:43 编辑Python with 语句
大部分人对with的认识我想是这样:
"with 是什么?
" with open("record.txt", 'w') as f:
# blablabla"
with 其实是一个上下文管理器,
而open 里面正好定义了这俩管理器,也就是 __enter__() 和 __exit__()。
with 后面的对象必须要有这俩玩意,没有就报错。
比如这样:
>>> with "asdasdasd" as test:
pass
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
with "asdasdasd" as test:
AttributeError: __enter__
报错是因为字符串类型是没有 __enter__ 滴!
然后来给大家分析下这俩东西:
以下解释转载自:
https://www.cnblogs.com/gengyufei/p/11341853.html
object.__enter__(self)
进入与此对象相关的运行时上下文。with语句将将此方法的返回值绑定到语句的as子句中指定的目标(如果有设置的话)
object.__exit__(self, exc_type, exc_value, traceback)
退出与此对象相关的运行时上下文。参数描述导致上下文退出的异常。如果上下文运行时没有异常发生,那么三个参数都将置为None。
如果有异常发生,并且该方法希望抑制异常(即阻止它被传播),则它应该返回True。否则,异常将在退出该方法时正常处理。
注意:
__exit__()方法不应该重新抛出传入的异常,这是调用者的职责。
------------------------------------------分割线------------------------------------
基础知识都学完了,让我们来实践一下吧!
自己定义一个类,里面包含上下文管理器:
class Test:
def func(self):
print("I amFUNC !")
def __enter__(self):
# __enter__通常都是返回self,用于对这个实例对象进行下一步操作,
# 后面会进行详细讲解。
print("I am __ENTER__ !")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("self:", self)
print("exc_type:", exc_type)
print("exc_value:", exc_value)
print("traceback:", traceback)
# return True
with Test() as tester:
tester.func()
运行结果:
I am __ENTER__ !
I amFUNC !
self: <__main__.Test object at 0x000001D91342DA30>
exc_type: None
exc_value: None
traceback: None
不难发现,with语句就是先调用 __enter__,然后执行缩进内的内容,
最后调用 __exit__ 退出。
那为什么这些 exc_type, exc_value 啥的都是None呢?
因为没有报错,所以它们默认为None。我们稍微修改下代码:
with Test() as tester:
tester.asdasdasd()
运行结果:
I am __ENTER__ !
self: <__main__.Test object at 0x00000216DAA97A30>
exc_type: <class 'AttributeError'>
exc_value: 'Test' object has no attribute 'asdasdasd'
traceback: <traceback object at 0x00000216DAAF7C80>
Traceback (most recent call last):
File "C:\Users\rzzl\Desktop\test2.py", line 19, in <module>
tester.asdasdasd()
AttributeError: 'Test' object has no attribute 'asdasdasd'
可以发现正常报错了,这时候,我们把那个 __exit__ 里面的 return True 放出来,看看效果:
I am __ENTER__ !
self: <__main__.Test object at 0x000002BAE60D7A30>
exc_type: <class 'AttributeError'>
exc_value: 'Test' object has no attribute 'asdasdasd'
traceback: <traceback object at 0x000002BAE5FEE180>
啊哈!不报错了!
所以,我们可以简单猜想下open函数的上下文管理器:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.close()
-----------------------------------------分割线------------------------------------------
__enter__ 的返回值可以是任何东西,比如一个字符串:
class Test:
def func(self):
print("I amFUNC !")
def __enter__(self):
# __enter__通常都是返回self,用于对这个实例对象进行下一步操作,
# 后面会进行详细讲解。
print("I am __ENTER__ !")
return "string"
def __exit__(self, exc_type, exc_value, traceback):
print("self:", self)
print("exc_type:", exc_type)
print("exc_value:", exc_value)
print("traceback:", traceback)
with Test() as tester:
print(tester.upper())
运行结果:
I am __ENTER__ !
STRING
self: <__main__.Test object at 0x00000224763D7A30>
exc_type: None
exc_value: None
traceback: None
符合预期。
------------------------------------------分割线------------------------------------
掌握了以上的知识,我们可以试着自己写个 with(用函数的方法实现)!
直接上代码:
(注意,本函数需要 sys 模块的 exc_info 函数,它返回的三元组正好是__exit__所需的参数。)
def WITH(cls,*func):
tester = cls.__enter__()
try:
for each in func:
try:
if (temp := eval(each)):
print(temp)
except:
continue
except Exception as e:
temp = sys.exc_info()
ex = cls.__exit__(temp, temp, temp)
if not ex: raise e
else:
cls.__exit__(None, None, None)
蒙了没?我想大部分人都不能一下子就看懂,要是真的能看明白,有鱼币奖励!
**** Hidden Message *****
用法:
WITH(类名(), "要执行的方法")
比如用于pynput.Listener:
WITH2(Listener(on_press = chk), "tester.join()")
注意,这个实例名字必须是tester,除非你改WITH源代码 @小甲鱼 申精~
不知道有转载部分还可不可以申精了 注:
我写的 with 还是很简陋的,各位大神们可以试试写个更强大的! 支持{:10_256:} 再次改进了一下,加了个参数:
class WITH2:
def __init__(self, cls, run, *func):
tester = cls.__enter__() # 先调用类的__enter__,返回一个实例化对象(这只是通常来讲,当然,__enter__也有可能返回个别的东西..)
try:
for each in func: # 遍历func元组,调用传入的函数
try:
if (temp := run(each)): # 如果使用了没有返回值的函数,会导致打印一个None
print(temp)
except:
continue
except Exception as e: # 如果产生报错,则修改__exit__参数
temp = sys.exc_info() # 返回个三元组,内容正好是__exit__所需参数
ex = cls.__exit__(temp, temp, temp)
if not ex: raise e # __exit__不是True就报错
else: cls.__exit__(None, None, None) # 没问题参数就直接填None
如果这个参数为eval,则以交互模式(不print也能出结果),exec则是标准形式,需要用print。 奥利给! {:10_298:}牛~支持 {:10_298:}牛~支持
{:10_298:}牛~支持
{:10_298:}牛~支持
{:10_298:}牛~支持
{:10_298:}牛~支持
{:10_298:}牛~支持
{:10_298:}牛~支持
{:10_298:}牛~支持
{:10_298:}牛~支持
{:10_298:}牛~支持
{:10_298:}牛~支持 666
qiuyouzhi 发表于 2020-6-7 07:20
@小甲鱼 申精~
不知道有转载部分还可不可以申精了
内容不是很丰满,并且有一半是转的,嘻嘻,所以不合适加精哦~ 小甲鱼 发表于 2020-6-8 00:32
内容不是很丰满,并且有一半是转的,嘻嘻,所以不合适加精哦~
支持 对了
您12点都没睡??{:7_145:}
页:
[1]