【原文】
The execution of a function introduces a new symbol table used for the local variables of the function. More precisely, all variable assignments in a function store the value in the local symbol table; whereas variable references first look in the local symbol table, then in the local symbol tables of enclosing functions, then in the global symbol table, and finally in the table of built-in names. Thus, global variables and variables of enclosing functions cannot be directly assigned a value within a function (unless, for global variables, named in a global
statement, or, for variables of enclosing functions, named in a nonlocal
statement), although they may be referenced.
The actual parameters (arguments) to a function call are introduced in the local symbol table of the called function when it is called; thus, arguments are passed using call by value (where the value is always an object reference, not the value of the object). 1 When a function calls another function, or calls itself recursively, a new local symbol table is created for that call.
A function definition associates the function name with the function object in the current symbol table. The interpreter recognizes the object pointed to by that name as a user-defined function. Other names can also point to that same function object and can also be used to access the function:
>>> fib <function fib at 10042ed0> >>> f = fib >>> f(100) 0 1 1 2 3 5 8 13 21 34 55 89
Coming from other languages, you might object that fib
is not a function but a procedure since it doesn’t return a value. In fact, even functions without a return
statement do return a value, albeit a rather boring one. This value is called None
(it’s a built-in name). Writing the value None
is normally suppressed by the interpreter if it would be the only value written. You can see it if you really want to using print()
:
>>> fib(0) >>> print(fib(0)) None
It is simple to write a function that returns a list of the numbers of the Fibonacci series, instead of printing it:
>>> def fib2(n): # return Fibonacci series up to n ... """Return a list containing the Fibonacci series up to n.""" ... result = [] ... a, b = 0, 1 ... while a < n: ... result.append(a) # see below ... a, b = b, a+b ... return result ... >>> f100 = fib2(100) # call it >>> f100 # write the result [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
This example, as usual, demonstrates some new Python features:
-
The
return
statement returns with a value from a function.return
without an expression argument returnsNone
. Falling off the end of a function also returnsNone
. -
The statement
result.append(a)
calls a method of the list objectresult
. A method is a function that ‘belongs’ to an object and is namedobj.methodname
, whereobj
is some object (this may be an expression), andmethodname
is the name of a method that is defined by the object’s type. Different types define different methods. Methods of different types may have the same name without causing ambiguity. (It is possible to define your own object types and methods, using classes, see Classes) The methodappend()
shown in the example is defined for list objects; it adds a new element at the end of the list. In this example it is equivalent toresult = result + [a]
, but more efficient.
4.8. More on Defining Functions
执行函数时使用的局部函数变量是一个新的符号表。更严谨些,一个函数中所有变量赋值后都将值存储在局部符号表;引用变量时先查看局部符号表,然后查看封闭函数的符号表,再是全局符号表,最后是内置名称表。因此,全局变量和封闭函数的变量可以被引用但不在调用函数中赋值(除非,用global语句命名全局变量。或者,用nonlocal语句命名封闭函数变量)。
函数调用的实际参数(参数)是函数局部符号表;因此,参数使用 call by value 传递(其中值始终是对象引用, 而不是对象的值)。当一个函数调用另一个函数,或者递归调用时,为调用创建一个新的局部符号表。
函数定义关联了函数对象的函数名,当前符号表。解释器通过函数名识别用户定义的函数。用函数名也可以指向相同的函数对象,访问该函数:
在其他语言,你认为fib对象不是一个函数而是一个过程,因为它不返回值。事实上,即使是没有return语句的函数也会返回一个值,尽管这是一个相当无聊的值。这个值就是None(它是一个内置名称)。如果None是唯一写入的值,通常解释器不显示None。 用print()可以输出它。
相较输出一个菲波那切数列,编写一个斐波那契数列函数更简单:
此示例演示了一些Python的新功能:
- return语句返回函数的值。return后没有表达式则返回None 。函数没有return在末尾自然结束也返回None。
- result.append(a)调用list对象的append方法。方法是一个“属于”对象并被命名为obj.methodname的函数,其中,obj是某个对象(这可能是一个表达式), methodname是由对象类型定义的方法的名称。不同的对象类型定义不同的方法。不同对象类型的方法可能具有相同的名称而不会引起歧义。(使用类可以定义自己的对象类型和方法,请参阅类)。在示例中,append()是列表对象的方法,是为列表在末尾添加一个新元素。它等价于result = result + [a],但效率更高。