One of our goals in this chapter is to isolate issues about thinking procedurally. As a case in point, let us consider that, in evaluating nested call expressions, the interpreter is itself following a procedure.
我们在本章中的目标之一是分离出关于程序性思维的问题。作为一个适当的例子,让我们考虑一下,在评估嵌套调用表达式时,解释器自身在遵循的一个过程。
To evaluate a call expression, Python will do the following:
为了评估调用表达式,Python会执行以下操作
- Evaluate the operator and operand subexpressions, then
- Apply the function that is the value of the operator subexpression to the arguments that are the values of the operand subexpressions.
1.计算运算符和操作数子表达式,然后 2.将作为运算符子表达式值的函数,应用于作为操作数子表达式值的参数。
Even this simple procedure illustrates some important points about processes in general. The first step dictates that in order to accomplish the evaluation process for a call expression we must first evaluate other expressions. Thus, the evaluation procedure is recursive in nature; that is, it includes, as one of its steps, the need to invoke the rule itself.
即使是这个简单的过程也说明了一般过程的一些要点。第一步规定,为了完成调用表达式的计算过程,我们必须首先计算其他表达式。因此,计算过程本质上是递归的;也就是说,它包括调用规则本身的需要,这是它的步骤之一。
For example, evaluating
例如,计算
>>> sub(pow(2, add(1, 10)), pow(2, 5))
2016
requires that this evaluation procedure be applied four times. If we draw each expression that we evaluate, we can visualize the hierarchical structure of this process.
需要应用求值过程4次。如果我们画出我们求值的每个表达式,我们可以直观地看到这个过程的层次结构。
This illustration is called an expression tree. In computer science, trees conventionally grow from the top down. The objects at each point in a tree are called nodes; in this case, they are expressions paired with their values.
这种图示被称为表达式树。在计算机科学中,树通常是自上而下生长的。树上每一个点的对象被称为节点;在这种情况下,它们是与数值配对的表达式。
Evaluating its root, the full expression at the top, requires first evaluating the branches that are its subexpressions. The leaf expressions (that is, nodes with no branches stemming from them) represent either functions or numbers. The interior nodes have two parts: the call expression to which our evaluation rule is applied, and the result of that expression. Viewing evaluation in terms of this tree, we can imagine that the values of the operands percolate upward, starting from the terminal nodes and then combining at higher and higher levels.
求出它的根,即顶部的完整表达式,需要首先求出作为其子表达式的分支。叶子表达式(也就是没有分支的节点)代表函数或数字。内部节点有两个部分:我们的计算规则所适用的调用表达式,以及该表达式的结果。从这棵树的角度来看求值,我们可以想象操作数的值是向上渗透的,从末端的节点开始,然后在越来越高的层次上组合。
Next, observe that the repeated application of the first step brings us to the point where we need to evaluate, not call expressions, but primitive expressions such as numerals (e.g., 2) and names (e.g., add). We take care of the primitive cases by stipulating that
接下来,观察一下第一步的重复应用,把带到我们需要求值的地方不是调用表达式,而是原始表达式,如数字(如2)和名字(如add)。我们通过规定以下内容来处理基本情况
- A numeral evaluates to the number it names,
- A name evaluates to the value associated with that name in the current environment.
- 一个数字求值为它所命名的数字,
- 一个名称求值为当前环境中与该名称关联的值
Notice the important role of an environment in determining the meaning of the symbols in expressions. In Python, it is meaningless to speak of the value of an expression such as without specifying any information about the environment that would provide a meaning for the name x (or even for the name add).
注意在确定的环境中表达式符号含义方面的重要作用。在 Python 中,如果没有指定任何关于环境的信息,为名称 x (甚至是名称 add) 提供意义,这样谈论一个表达式的值是毫无意义的。
>>> add(x, 1)
Environments provide the context in which evaluation takes place, which plays an important role in our understanding of program execution.
环境为求值的地方提供了上下文,它在我们理解程序执行起到一个重要的作用
This evaluation procedure does not suffice to evaluate all Python code, only call expressions, numerals, and names. For instance, it does not handle assignment statements. Executing
这个求值过程并不合适所有的Python代码的求解,只能调用表达式、数字和名称。 例如,它不会处理赋值语句,执行
>>> x = 3
does not return a value nor evaluate a function on some arguments, since the purpose of assignment is instead to bind a name to a value. In general, statements are not evaluated but executed; they do not produce a value but instead make some change. Each type of expression or statement has its own evaluation or execution procedure.
既不返回值,也不对某些参数的函数求值,因为赋值的目的是将名称绑定到值。一般来说,语句不是求值而是执行;它们不产生价值,而是产生一些变化。每种类型的表达式或语句都有自己的求值或执行过程。
A pedantic note: when we say that “a numeral evaluates to a number,” we actually mean that the Python interpreter evaluates a numeral to a number. It is the interpreter which endows meaning to the programming language. Given that the interpreter is a fixed program that always behaves consistently, we can say that numerals (and expressions) themselves evaluate to values in the context of Python programs.
一个保守的注释: 当我们说“一个数字等于一个数字”时,我们实际上是指 python 解释器将一个数字等于一个数字。正是解释器赋予了编程语言意义。鉴于解释器是一个固定的程序,它的行为总是一致的,我们可以说数字(和表达式)本身在 python 程序的上下文中计算为值。