原文:http://www.swaroopch.com/notes/python/#functions,基于文章的 3.0 版进行翻译。
函数是可复用的代码块。它们允许你给一段语句块命名,你可以通过在程序的任何地方和任意次数使用指定的名字运行代码块。这被称为调用函数。我们已经用过很多如 len
和 range
的内置函数了。
函数可能是在建立任何非凡软件中最重要的概念,所以在这一章节我们将会讨论函数的各个方面。
使用 def
关键字来定义函数。在关键字后面添加代表函数名字的标识符,接着是一对用于包含一些变量名的小括号,最后以冒号结束该行。接着就是函数的语句块。下面的例子是一个简单的函数:
例子(名为 function1.py
):
def say_hello():
# block belonging to the function
print 'hello world'
# End of function
say_hello() # call the function
say_hello() # call the function again
输出:
$ python function1.py
hello world
hello world
工作原理
我们使用上述的语法定义一个名为 say_hello
的函数。这个函数不带参数,因此小括号里没有声明变量。函数的参数是函数的输入,所以我们可以将不同的值传进函数并且得到对应的结果。
注意到我们可以调用同一个函数两次,这意味着我们不需要重复写相同的代码。
1. 函数参数
函数可以带参数,这些参数是你提供给函数的一些值,所以函数可以使用这些值做一些事情。这些参数正如变量,除了这些变量的值是在我们调用函数的时候定义的,并且这些变量在函数运行的时候已经被赋值。
参数放在函数定义的小括号对立面,并且用逗号隔开。当我们调用函数时,我们用同样的方式提供值。请注意这里引用的术语——函数定义里的名字叫做参数(parameters),你调用函数所提供的值叫引数(arguments)。
例子(名为 function_param.py
):
def print_max(a, b):
if a > b:
print a, 'is maximum'
elif a == b:
print a, 'is equal to', b
else:
print b, 'is maximum'
# directly pass literal values
print_max(3, 4)
x = 5
y = 7
# pass variables as arguments
print_max(x, y)
输出:
$ python function_param.py
4 is maximum
7 is maximum
工作原理
上面的代码中,我们定义了一个名为 print_max
的函数,该函数使用两个参数 a
和 b
。我们使用简单的 if..else
语句找出较大的数,然后打印较大的数字。
第一次调用 print_max
函数,我们直接提供数字用作引数。在第二次调用时,我们调用函数并将变量作为引数传进该函数。print_max(x, y)
将引数 x
的值赋给参数 a
,将引数 y
的值赋给参数 b
。两种方法中,printMax 函数都是同样地工作。
2. 局部变量
当你在一个函数定义中声明变量时,函数里面的这些变量与函数外面同名的变量没有任何关系——即变量名是函数局部的。这被称作变量的作用域。所有的变量都有作用域,这个作用域在声明变量名的时候开始。
例子(名为 function_local.py
):
x = 50
def func(x):
print 'x is', x
x = 2
print 'Changed local x to', x
func(x)
print 'x is still', x
输出:
$ python function_local.py
x is 50
Changed local x to 2
x is still 50
工作原理
第一次打印出来 x 的值是由函数正文的第一行产生的,Python 使用的参数值声明在主区块,在函数定义的上方。
接着,我们将 2
赋给 x
。x
是我们函数的局部变量。所以,当我们改变函数里面的 x
的值时,定义在主区块的 x
不受影响。
最后的 print
语句,显示了定义在主区块 x
的值,从而确认它不会被之前调用的函数的局部变量所影响。
3. 全局声明
如果你想将值赋给一个定义在程序顶层的名字(即不在任何作用域内,如函数或者类),那么你必须告诉 Python 这个名字不是局部的,而是全局的。为此,我们使用 global
语句。不可能不用 global
语句来将值赋给一个定义在函数外面的变量。
你可以使用定义在函数外面那些变量的值(假设函数里面没有与该变量同名的变量)。然而,我们并不鼓励且应该避免这样做,因为这样对于程序的阅读者来说不够清晰,他们不容易找到变量定义的地方。使用 global
语句足够清晰地表明了变量定义在最外层的代码块。
例子(名为 function_global.py
):
x = 50
def func():
global x
print 'x is', x
x = 2
print 'Changed global x to', x
func()
print 'Value of x is', x
输出:
$ python function_global.py
x is 50
Changed global x to 2
Value of x is 2
工作原理
global
语句用来声明 x
是一个全局变量——所以,当我们在函数里面赋值给 x
时,那个修改会在主代码块中使用 x
的值时反映出来。
你可以用同一个 global
语句指定多个全局变量,例如 global x, y, z
。
4. 参数默认值
对于一些函数,你可能想要令一些参数可选和使用默认值以防用户不想提供值给这些参数。为此,可以使用参数默认值。你可以这样来指定参数默认值:在函数定义的参数名后面添加赋值运算符(=
)和默认值。
注意到参数默认值应该要是一个常量。更准确地说,参数默认值应该是不可变的(immutable)——这将会在以后的章节中解释。现在,只需要记住即可。
例子(名为 function_default.py
):
def say(message, times=1):
print message * times
say('Hello')
say('World', 5)
输出:
$ python function_default.py
Hello
WorldWorldWorldWorldWorld
工作原理
名为 say
的函数按指定的次数打印一个字符串。如果我们不提供一个值,那么默认地,该字符串只会打印一次。我们通过指定参数 times
的参数默认值为 1
来达到上述目的。
在第一次使用 say
的地方,我们只提供字符串,函数打印该字符串一次。在第二次使用 say
的地方,我们提供了字符串和一个引数 5
来说明我们想让 say
函数打印字符串 5 次。
注意:只有那些在参数列表末尾的参数可以提供参数默认值,即在函数参数列表中,你不能将一个带有参数默认值的参数放在一个不带参数默认值的参数前面。
这是因为传进函数的值是按照参数的位置进行复制。例如,def func(a, b=5)
是正确的,但是 def func(a, b=5)
是无效的。
5. 关键字参数
如果你有一些带有很多参数的函数,并且你想指定参数中的某几个,那么你可以通过对参数进行命名来将值传给那些参数——这称作关键字参数——我们使用名字(关键字)来代替位置(我们一直使用的方式)指定函数的参数。
这样做有两个好处——一,可以更容易地使用函数,因为我们不需要担心参数的顺序。二,如果其它参数有参数默认值,那么我们可以将值给那些我们想要赋值的参数。
例子(名为 function_keyword.py
):
def func(a, b=5, c=10):
print 'a is', a, 'and b is', b, 'and c is', c
func(3, 7)
func(25, c=24)
func(c=50, a=100)
输出:
$ python function_keyword.py
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and c is 24
a is 100 and b is 5 and c is 50
工作原理
函数 func
有一个不带参数默认值的参数,和两个带有参数默认值的参数。
第一个使用 func
的地方,func(3, 7)
,参数 a
得到 3
,参数 b
得到 7
和参数 c
得到默认值 10
。
第二个使用的地方 func(25, c=24)
,由于引数位置的关系,变量 a
得到 25
这个值。然后,由于关键字参数,参数 c
得到 24
。变量 b
取默认值 5
。
第三个使用的地方 func(c=50, a=100)
,我们为所有指定的值使用关键字参数。注意到虽然在函数定义中,a
是定义在 c
之前,但是我们也可以在传递参数时,将 c
放在 a
前面。
6. 可变参数
有时候你可能想要定义一个带任意数量参数的函数,即参数数目可变,这可以通过使用星号来完成(名为 function_varargs.py
):
def total(initial=5, *numbers, **keywords):
count = initial
for number in numbers:
count += number
for key in keywords:
count += keywords[key]
return count
print total(10, 1, 2, 3, vegetables=50, fruits=100)
输出:
$ python function_varargs.py
166
工作原理
当我们声明一个像 *param
这样标了星号的参数时,从该点到末尾的所有位置参数都会以元组的形式收集起来,称为 ‘param’。
相同地,当我们声明一个像 **param
这样标了两个型号的参数时,从该点到末尾的所有关键字参数都会以字典的形式收集起来,称为 ‘param’。。
7. return 语句
return
语句用于从一个函数中返回,即跳出该函数。我们也可以从函数中返回一个值。
例子(名为 function_return.py
):
def maximum(x, y):
if x > y:
return x
elif x == y:
return 'The numbers are equal'
else:
return y
print maximum(2, 3)
输出:
$ python function_return.py
3
工作原理
maximum
函数返回参数中的最大值,在这个例子中就是提供给函数的数字。该函数使用一个简单的 if..else
语句找到更大的值,然后返回该值。
注意到一个不带值的 return
语句相当于 return None
。None
在 Python 中是代表空的特殊类型。例如,它用来表明如果一个变量的值为 None
,那么该变量没有值。
每个函数在末尾都会隐式地包含一个 return None
语句,除非你添加了自己的 return
语句。这可以通过运行 print some_function()
来查看,其中,some_function
像下面一样不要使用 return
语句:
def some_function():
pass
在 Python 中使用 pass
语句来指明一个空语句块。
提示:有一个内置的函数 max
已经实现了查找最大值的功能,所以可以在任何时候使用这个内置函数。
8. DocStrings
Python 有一个很好的功能叫文档字符串(documentation strings),通常会简称为 docstrings。文档字符串是你应该好好利用的一个重要的工具,因为这样可以更好地文档化程序并且使程序更容易理解。令人惊讶的是,我们甚至可以在程序正在运行的时候,从一个函数中获得文档字符串。
例子(名为 function_docstring.py
):
def print_max(x, y):
'''Prints the maximum of two numbers.
The two values must be integers.'''
# convert to integers, if possible
x = int(x)
y = int(y)
if x > y:
print x, 'is maximum'
else:
print y, 'is maximum'
print_max(3, 5)
print print_max.__doc__
输出:
$ python function_docstring.py
5 is maximum
Prints the maximum of two numbers.
The two values must be integers.
工作原理
函数第一行逻辑行中的字符串是该函数的文档字符串。文档字符串也适用于模块和类。
按照约定,一个文档字符串是由多行字符串组成,并且首行以一个大写字母开头,以一个小圆点结尾。接着第二行是空白。任何详细的描述始于第三行。强烈建议在你的有意义的函数中,按照这个约定来添加你的文档字符串。
我们可以通过使用函数的 __doc__
(注意是双下划线)属性来访问 print_max
函数的文档字符串。只要记住 Python 把每件事物都当做一个对象,当然也包括函数。我们将会在类章节中学到更多关于对象的知识。
如果你在 Python 有使用过 help()
,那么你已经看到过文档字符串的用法!它做的就是提取函数的 __doc__
属性然后整齐的显示给你。你可以尝试在上面的函数使用它——只需在你的程序中包含 help(print_max)
。记住按下 q
可以退出 help
。
自动化可以按照这种方式从你的程序中提取出文档。因此,我强烈建议你在你写的任何有意义的函数中使用文档字符串。伴随 Python 发行版的 pydoc
命令的工作方式类似于 help()
那样来提取文档字符串。
9. 总结
虽然我们看到了函数的很多方面,但是我们仍然没有涉及到各个方面。无论如何,我们已经覆盖了大多数在日常使用中,你可能用到 Python 函数的知识。