马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 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__ 滴!
然后来给大家分析下这俩东西:
object.__enter__(self)
进入与此对象相关的运行时上下文。with语句将将此方法的返回值绑定到语句的as子句中指定的目标(如果有设置的话)
object.__exit__(self, exc_type, exc_value, traceback)
退出与此对象相关的运行时上下文。参数描述导致上下文退出的异常。如果上下文运行时没有异常发生,那么三个参数都将置为None。
如果有异常发生,并且该方法希望抑制异常(即阻止它被传播),则它应该返回True。否则,异常将在退出该方法时正常处理。
注意:
__exit__()方法不应该重新抛出传入的异常,这是调用者的职责。
------------------------------------------分割线------------------------------------
基础知识都学完了,让我们来实践一下吧!
自己定义一个类,里面包含上下文管理器:
class Test:
def func(self):
print("I am FUNC !")
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 am FUNC !
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 am FUNC !")
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())[code]
运行结果:
[code]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[0], temp[1], temp[2])
if not ex: raise e
else:
cls.__exit__(None, None, None)
蒙了没?我想大部分人都不能一下子就看懂,要是真的能看明白,有鱼币奖励!
用法:
WITH(类名(), "要执行的方法")
比如用于pynput.Listener:
WITH2(Listener(on_press = chk), "tester.join()")
注意,这个实例名字必须是tester,除非你改WITH源代码 |