【发布时间】:2016-06-19 18:27:28
【问题描述】:
从 Python 2 到 Python 3 的基本变化之一是使 print 成为一个函数 - 对我来说,考虑到它的结构,这非常有意义。为什么raise 和del 语句也不起作用?尤其是在 raise 的情况下,它似乎正在接受一个参数并用它做一些事情,就像一个函数一样。
【问题讨论】:
标签: python function python-3.x structure
从 Python 2 到 Python 3 的基本变化之一是使 print 成为一个函数 - 对我来说,考虑到它的结构,这非常有意义。为什么raise 和del 语句也不起作用?尤其是在 raise 的情况下,它似乎正在接受一个参数并用它做一些事情,就像一个函数一样。
【问题讨论】:
标签: python function python-3.x structure
raise 和 del 绝对不同于函数,每个都有不同的原因:
raise 退出当前执行流程;字节码解释的正常流程被中断,堆栈被展开,直到找到下一个异常处理程序。函数不能这样做,而是创建一个新的堆栈帧。
del 不能是函数,因为你必须指定一个特定的目标;您不能只使用任何表达式,删除的内容取决于给定的语法;如果您使用订阅,则会删除容器中的给定元素,或者从当前命名空间中删除名称。要删除的正确命名空间也取决于删除名称的范围。见del statement grammar definition:
del_stmt ::= "del" target_list
函数不能从父命名空间中删除项目,也不能区分订阅表达式的结果或直接引用的结果。您将 objects 传递给函数,但传递给 del 语句时,您传递名称和上下文(可能由解释器在删除本地或全局名称时)。
另一方面,print 不需要与当前命名空间或堆栈框架的特殊关系,也不需要特殊的语法约束来完成它的工作。它只是应用程序级别的纯粹功能。全局 sys.stdout 引用可以被函数访问,就像被解释器访问一样。因此它不需要是一个语句,并且通过将它移动到一个函数中,可以获得额外的好处,例如能够覆盖它的行为并在 Python 版本中更快地对其进行创新。
请注意,raise 语句的 部分 已移至应用程序级代码;在 Python 2 中,您可以使用以下方法将回溯附加到引发的异常:
raise ExceptionClass, exception_value, traceback_object
在 Python 3 中,将回溯附加到异常已移至异常本身:
raise Exception("foo occurred").with_traceback(tracebackobj)
【讨论】:
https://www.python.org/dev/peps/pep-3105/ 列出了为什么 print 成为函数的原因列表。在五个原因中,(IMO)最相关的一个是:
print 是唯一具有专用语句的应用程序级功能。
正如 Alex Martelli 所解释的,https://stackoverflow.com/a/1054062:
Python 语句是 Python 编译器必须特别注意的事情——它们可能会改变名称的绑定,可能会改变控制流,和/或可能需要在某些条件下从生成的字节码中完全删除(后者适用断言)。 print 是 Python 2 中这个断言的唯一例外;通过从语句列表中删除它,Python 3 删除了一个异常,使一般断言“保持不变”,因此是一种更常规的语言。
del 和raise 显然会改变名称的绑定/改变控制流,因此它们都可以。
【讨论】: