Python中的with是测试常用到的资源打开利器

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"在我们完成自动化测试代码的时候,总会遇见各种读取文本文件、读取Excel等类型的操作。这种代码我们时刻都要记得打开文件后要关闭文件。往往关闭文件却是我们常常忘记的。针对上述这样的情况,python提供了with就可以完美解决这个问题,这也是python的语法糖。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"Syntactic sugar,也就是语法糖,它指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。语法糖让程序更加简洁,有更高的可读性。语法糖就是为了避免coder出现错误并提高效率的语法层面的一种优雅的解决方案。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"一个常规的文件打开代码"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"下面是一个常规的打开文件的代码,那么你可以从下面代码中看出什么问题吗?"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" rf= open('crisschan.txt','r')\n\n print(rf.readlines())\n\n rf.close()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"上面代码在读取文件过程中如果发生异常,那么close()函数就没有办法被执行到了,这也就导致了文件没有办法关闭了。因此,很多教程上都告诉大家要用try except将文件读取的异常捕获到,那么我们改造一下如下:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" try:\n\n \t\trf = open('email.txt','r')\n\n \t\tprint(rf.readlines())\n\n except:\n\n \t\tprint('Oooooops!What\\'s up!')\n\n finally:\n\n \t\trf.close()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"好了,上面的代码无论如何我们都会执行close函数了,这样是不是已经很好了。但是上面的代码太繁琐了,这样的coding段,python提供了with,让上述的代码更简单:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"with open('email.txt','r') as rf:\n\n print(rf.readlines())"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"上面是不是很简洁,是不是也很优雅呢。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":" with是怎么干活的"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"with context_expression [as target(s)]:\n\n \t\tdo_somthing()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"上述代码片段中,`context_expression`会返回一个上下文管理器对象,这个对象并不赋值给`as`后的`target(s)`,而是上下文管理器的`__enter__()`函数的返回值赋值给 `target(s)`。当with全部的代码段都执行完成后,会调用`__exit__()`。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"具体例子如下:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"class SampleWith(object):\n\n def __init__(self):\n\n \t\tprint('init this class')\n\n def __enter__(self):\n\n \t\tprint('this is __enter__')\n\n \t\treturn 'CrissChan'\n\n def __exit__(self, exc_type, exc_val, exc_tb):\n\n \t\tprint('this is __exit__')\n\n def call(self):\n\n \t\tprint('call funtion')\n\n if __name__ == '__main__':\n\n \t\twith SampleWith() as sw:\n\n \t\t\t\tprint('sw is :',sw)\n\n \t\t\t\tsw.call()"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"运行完后,输入如下:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"init this class\n\n this is __enter__\n\n sw is : CrissChan\n\n this is __exit__\n\n Traceback (most recent call last):\n\n File \"/Users/crisschan/PycharmProjects/try_space/flv2mp4.py\", line 24, in \n\n sw.call()\n\n AttributeError: 'str' object has no attribute 'call'"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"那下面我来给你解释一下上面的代码段以及结果输出。"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"1、在main函数中我们使用with调用了SampleWith(),这是时候我们就会看到了我们险实力话了一个SampleWith类,调用了他的`__init__(self)`构造函数,"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"2、接下来因为我们使用了with这个语法糖,因此下面调用了`__enter__(self)`"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"3、在后面我使用了`as sw`,也就是我将`__enter__(self)`的return赋值给了`sw`,那么也就是说`sw`存储的是字符串`CrissChan`,那么也就打印了`sw is : CrissChan`"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"4、后面调用了sw.call()就出了问题,因为字符串没有call方法。但是仍旧进入了`__exit__(self, exc_type, exc_val, exc_tb)`函数。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"下面我将上面有报错的代码修改一下,如下:"}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"class SampleWith(object):\n\n def __init__(self):\n\n \t\tprint('init this class')\n\n def __enter__(self):\n\n \t\tprint('this is __enter__')\n\n \t\treturn 'CrissChan'\n\n def __exit__(self, exc_type, exc_val, exc_tb):\n\n \t\tprint('this is __exit__')\n\n def call(self):\n\n \t\tprint('call funtion')\n\n if __name__ == '__main__':\n\n \t\twith SampleWith() as sw:\n\n \t\t\tprint('sw is :',sw)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"上面代码就不会报错了。从上面可以看出就算中间除了异常,放在`__exit__()`中的逻辑段还是会被执行的。想要了解更多请看官方的文档[pep-403]("},{"type":"text","marks":[{"type":"underline"},{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"https://www.python.org/dev/peps/pep-0343/"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":")"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"特别备注:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":" exit()方法中有3个参数, exc_type, exc_val, exc_tb,这些参数在异常处理中相当有用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":" exc_type: 错误的类型"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":" exc_val: 错误类型对应的值"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":" exc_tb: 代码中错误发生的位置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章