Neu*_*onQ 10 python coding-style indentation with-statement zen-of-python
我不打算简单地浪费你的时间,但是:它是否也发生在你身上,而使用Python的with声明,它确实与"禅宗的Python"的第5行相反,"扁平比嵌套好"?任何开明的Python大师能否与我分享他们对此的一些见解?
(我总是发现每次使用时我的代码中都会出现一个更多级别的缩进with而不是f.close()......并且它不会像我不会try: ... finally: ...反正使用那样因此with我仍然无法获益,即使我渐渐喜欢并越来越多地了解Python ...)
@glglgl(对不起,我找不到在评论中编写代码的方法):是的,但如果with顺便说一下,你的代码就会变成:
try:
with file(...) as f:
...
except IOError:
...
Run Code Online (Sandbox Code Playgroud)
...并且只使用没有这try是人们最终做的hacky"一次使用"代码,他们使用f.close()而不是反正(这是不好的,因为如果在他们之前抛出异常,文件可能不会被关闭f.close()),所以对于"hacky"代码,人们只是不使用with因为,我不知道,我猜他们只是发现它太"花哨"而且对于结构良好的代码它不会带来任何好处,所以它似乎我没有真正的世界用例...这是我真正的思考.
你已经提到它了:做起来比较干净
f = file(...)
try:
# do work on file
finally:
f.close()
Run Code Online (Sandbox Code Playgroud)
而不仅仅是在文件操作后关闭 - 如果发生异常将无法达到.
如果比较try/finally到with,你有压痕的同一水平,所以你不会失去任何东西.但是,如果你进行异常处理,你会有一个更多级别的缩进,这确实违背了所说的Zen点.
OTOH,with封装东西并使它们更容易和更易读,这是其他禅宗方面.
我似乎不可能始终完全遵循每一个禅宗方面; 有时你必须权衡一个与另一个.在这种情况下,您"失去"一级缩进,但您可以获得更好的可读性和可维护性.后者似乎对我有利.
请注意,Python的Zen也说:
简单比复杂更好.
复杂比复杂更好.
和
可读性很重要.
在with语句中使用上下文管理器提供了多种功能:
with open(..) as f很容易理解)你不能指向Python的Zen中的一个项目,并且认为所有Python代码必须始终满足所有项目.例如,如果以可读和正确的方式解决特定问题的最小缩进级别为4,那么就是这样:如果缩进级别为3使代码可读性降低,则只留下代码(四个是好的).
是的,Python的Zen说"Flat比嵌套更好",但它不是我们关心的唯一特征; 它还指出"简单比复杂更好".它的美妙之with处在于它实际上遵循这两个原则,我将在下面解释.
每当你发现自己对Python中的一个特性进行哲学思考时,可能需要查阅Python增强建议(PEP)以了解该功能背后的动机.在这种情况下,PEP 343 - "with"声明在摘要中预先说明:
这个PEP在Python语言中添加了一个新的"with"语句,可以分解try/finally语句的标准用法.
保理try/finally语句使代码更简单,更易读.
然而,PEP 343比提供一些简单的语法糖更深入.它建立了上下文管理器协议:
紧跟语句中with关键字之后的表达式是"上下文表达式",因为该表达式提供了上下文管理器在语句体持续时间内建立的运行时环境的主要线索.
使用上下文管理器协议,API编写器可以帮助隐藏复杂性并确保在多线程上下文中正确获取/释放资源.
但是with,PEP 343的例子12显示了该陈述的真正美妙,它解释了:
一个"嵌套"上下文管理器,它从左到右自动嵌套提供的上下文,以避免过度缩进.
使用nested()上下文管理器,您可以获取如下所示的代码:
with a as x:
with b as y:
with c as z:
# Perform operation
Run Code Online (Sandbox Code Playgroud)
把它变成这个:
with nested(a, b, c) as (x, y, z):
# Perform operation
Run Code Online (Sandbox Code Playgroud)
请注意,这nested()是在Python 2.5中引入的,但是从版本2.7开始,它不推荐使用这种多上下文管理器语法形式:
with a as x, b as y, c as z:
# Perform operation
Run Code Online (Sandbox Code Playgroud)
显然,这不仅更简单,更易读,而且比嵌套更扁平.因此,使用with是遵循无为的路径:)
更新:回应对Simeon Visser的回答这里的回答是一个例子,当你想要将两个(或更多)文件的内容压缩在一起时,你可以使用多个上下文管理器一次打开多个文件,如果打开其中一个文件失败将导致整个过程失败并正确关闭打开的每个文件:
from itertools import izip
with open("/etc/passwd") as a, open("/etc/group") as b, open("/etc/shadow") as c:
for lines in izip(a,b,c):
print map(lambda x: x.split(':')[0], lines)
Run Code Online (Sandbox Code Playgroud)
运行这个例子两次; 一次作为root,一次作为普通用户.假设您保存此文件作为ziptogether.py第一次尝试以root 身份调用它sudo python ziptogether.py并且它将成功,但是作为普通用户调用它将python ziptogether.py失败,因为您没有读取权限/etc/shadow.当它失败时,上下文管理器将确保在执行超出with语句范围时正确关闭在失败之前成功打开的文件.