Python的禅与声明 - 哲学思考

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python的禅与声明 - 哲学思考相关的知识,希望对你有一定的参考价值。

我不打算简单地浪费你的时间,但是:它也发生在你身上,同时使用Python的with语句,它确实与“禅宗的Python”的第5行相反,“扁平比嵌套好” ?任何开明的Python大师能否与我分享他们对此的一些见解?

(我总是发现每次使用with而不是f.close()时,我的代码中会出现一个更多级别的缩进...而且不管怎样我不会使用try: ... finally: ...因此with的好处仍然无法避免,即使我越来越喜欢和理解Python ......)


@glglgl(对不起,我找不到在评论中编写代码的方法):是的,但是如果你采用with方式,你的代码就会变成:

try:
    with file(...) as f:
        ...
except IOError:
    ...

...并且在没有try的情况下使用是人们最终做的hacky“一次使用”代码,他们使用f.close()而不是反正(这很糟糕,因为如果抛出异常,文件可能不会被关闭在他们的f.close()之前),所以对于“hacky”代码人们只是不使用with因为,我不知道,我猜他们只是发现它太“花哨”而且对于结构良好的代码它不会带来任何好处,所以在我看来,没有真正的世界用例...这是我真正的思考。

答案

是的,The Zen of Python说“Flat比嵌套好”,但它不是我们关心的唯一特征;它还指出“简单比复杂更好”。 with的美妙之处在于它实际上遵循这两个原则,我将在下面解释。

每当你发现自己对Python中的一个特性进行哲学思考时,可能值得查看Python Enhancement Proposals (PEPs)以了解该功能背后的动机。在这种情况下,PEP 343 -- The "with" Statement在摘要中预先说明了这一点:

这个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

把它变成这个:

with nested(a, b, c) as (x, y, z):
             # Perform operation

请注意,nested()是在Python 2.5中引入的,但是从版本2.7开始,它不推荐使用这种多上下文管理器语法形式:

with a as x, b as y, c as z:
             # Perform operation

显然,这不仅更简单,更易读,而且比嵌套更扁平。因此,使用with遵循無爲的路径:)

更新:作为对comments on Simeon Visser's answer的回应,这里有一个例子,当你想要将两个(或更多)文件的内容压缩在一起时,你可以使用多个上下文管理器一次打开多个文件,这样如果打开其中一个文件失败它会使整个事情失败并正确关闭所打开的每个文件:

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)

运行这个例子两次;一次作为root,一次作为普通用户。假设您将此文件保存为ziptogether.py首先尝试使用sudo python ziptogether.py以root身份调用它并且它将成功,但是使用python ziptogether.py作为普通用户调用它将失败,因为您没有权限读取/etc/shadow。当它失败时,上下文管理器将确保在执行超出with语句范围时正确关闭在失败之前成功打开的文件。

另一答案

请注意,Python的Zen也说:

简单比复杂更好。

复杂比复杂更好。

可读性很重要。

with语句中使用上下文管理器提供了多种功能:

  • 文件始终关闭时的正确行为
  • 可读性(with open(..) as f是可以理解的)

你不能指向Python的Zen中的一个项目,并且认为所有Python代码必须始终满足所有项目。例如,如果以可读和正确的方式解决特定问题的最小缩进级别为4,那么就是这样:如果缩进级别为3使代码可读性降低,则只留下代码(四个是好的)。

另一答案

你已经提到它了:做起来比较干净

f = file(...)
try:
    # do work on file
finally:
    f.close()

而不仅仅是在文件操作后关闭 - 如果发生异常将无法达到。

如果你将try/finallywith进行比较,你会有相同的缩进程度,所以你不会丢失任何东西。但是,如果你进行异常处理,你会有一个更多级别的缩进,这确实违背了所说的Zen点。

OTOH,with封装了东西,使得使用它们更容易,更易读,这是其他禅宗方面。

我似乎不可能始终完全遵循每一个禅宗方面;有时你必须权衡一个与另一个。在这种情况下,您“失去”一级缩进,但您可以获得更好的可读性和可维护性。后者似乎对我有利。

另一答案
"Flat is better than nested"

那么,什么是平的?

import thirdparty
print "I Like Pie!"

VS

import org.example.thirdparty.something
System.out.println("I Like Cake")

等等...

Python的Zen不会简单地对代码强制执行缩进限制。它鼓励您编写可读(因而更好)的代码。如果你的with语句在一个只能由3层对象(等等,one.two.three.func())访问的函数中,那么这就是一个问题。

否则,三个缩进级别与任何级别一样好。

另一答案

更喜欢with的原因是你不需要手动配对相关的操作(比如open(...) / .close();但是with结构更通用 - 不仅用于处理文件)。这是重要的,即在由于源代码中不清楚可见的原因而可能不执行第二操作的情况下。你告诉机器为我照顾它,机器比人类更好。通过这种方式,您可以摆脱可能难以找到的一组令人讨厌的错误。

顺便说一句,你应该使用open(...)而不是file(...)。 Python 3对file(...)一无所知,否则你将不得不修改你的代码。

以上是关于Python的禅与声明 - 哲学思考的主要内容,如果未能解决你的问题,请参考以下文章

与技术无关,但却值得码农们好好读一读的怪书:禅与摩托车维修艺术

常用python日期日志获取内容循环的代码片段

爱飙车的程序员,代码禅与摩托车丨二叉树视频

VSCode自定义代码片段——声明函数

VSCode自定义代码片段8——声明函数

禅与计算机程序设计艺术使用 16 门编程语言实现斐波那契数列:循环控制指令与函数递归思想