1.2.9 函数
函数是可重用的程序片段。你可以给一块语句一个名字,并且在你的程序的任何地方使用指定的名字运行任何次数。这就是所谓的函数调用。我们已经使用了许多内置函数, 如len
和range
。
在任何有价值软件中,函数的概念都是最重要的基础(对于任何编程语言都一样),所以,在这一章,我们将探索函数的各各方面。
定义函数使用def
关键字。在这个关键字之后是标识函数的名字,其次是在一对括号中可以附上一些变量名,最后在行的末尾是冒号。接下来是语句块--函数的内容。一个例子将展示这些,这实际上是非常简单的:
例子 (保存为function1.py):
def sayHello():
# 函数的语句块
print('世界您好!')
# 函数在此结束
sayHello() # 调用函数
sayHello() # 再次调用函数
输出:
$ python function1.py
世界您好!
世界您好!
它是如何工作的:
我们使用上述的语法,定义了一个称为sayHello
函数。这个函数没有参数,因此没有在圆括号中声明变量。函数的参数只是输入到函数中,以便我们可以给它传递不同的值返回相应的结果。
注意,我们可以调用相同的函数两次,这意味着我们不需要再写同样的代码。
函数的参数
一个函数可以带参数--你提供给函数的值,利用这些值该函数可以做一些事情。这些参数就像变量,所不同的是当我们调用函数时这些变量的值已经被定义,当函数运行时,它们已经有了指定的的值。
参数是在函数定义中在一对括号中指定,之间用逗号分隔。当我们调用这个函数,我们以同样的方式提供这些值。注意使用的术语——在函数的定义中给出的名字叫形参,而在函数调用时您提供的值被称为实参。
例子 (保存为func_param.py):
def printMax(a, b):
if a > b:
print(a, '大')
elif a == b:
print(a, '等于', b)
else:
print(b, '大')
# 直接给出字面值
printMax(3, 4)
x = 5
y = 7
# 给出参数的变量
printMax(x, y)
输出:
$ python func_param.py
4 大
7 大
它如何工作的:
在这里,我们定义了一个称为printMax
的函数,它拥有a
和b
的两个参数。我们使用简单的if..else
语句找出比较大的数,然后打印较大的数。
我们第一次调用函数printMax
,我们直接提供了数字作为参数。在第二种情况下,我们调用函数使用变量作为参数。printMax(x, y)
把实参x
分配给形参a
,y
分配给b
。在这两种情况下,printMax
函数以同样方式工作。
局部变量
你在函数定义中声明的变量,他们与在函数外使用的其它同名变量没有任何关系,即变量名称对函数来说是局部的。这叫变量的范围。所有变量都有它们被声明的块的范围,从名称定义的点开始。
例子 (保存为func_local.py):
x = 50
def func(x):
print('x等于', x)
x = 2
print('局部变量x改变为', x)
func(x)
print('x一直是', x)
输出:
$ python func_local.py
x等于50
局部变量x改变为2
x一直是50
它是如何工作的:
第一次,我们使用函数体中第一行打印变量x的值,Python使用在主块中,函数定义上声明的实参。
接下来,我们给x
赋值为2
,变量为x
对我们的函数来说是局部变量,因此在函数中当我们改变x
的值时,在主块中定义的变量x
不受影响。
最后调用的print
函数,显示在主块中定义的变量x
,说明它不受在前面调用函数的局部变量的影响。
使用全局声明
如果你想给在顶层的程序(即未在任何函数或类之中)定义的变量赋值,那么你必须告诉Python,变量不是局部的,而是全局的。我们使用global
语句,没有global
语句赋值给一个在函数外定义的变量是不可能的。
您可以使用这些在函数外定义的变量的值(假设在函数内没有同名的变量)。然而,这并不鼓励,应该避免,因为这使程序的读者不清楚变量是在哪里定义的,使用 global
语句就非常清楚,变量定义在一个最外的块中。
例子 (保存为func_global.py):
x = 50
def func():
global x
print('x的值是', x)
x = 2
print('全局变量x改为', x)
func()
print('x的值是', x)
输出:
$ python func_global.py
x的值是50
全局变量to改为2
x的值是2
它是如何工作的:
global
语句用来声明x
是全局变量,当我们在函数内给x
赋值时,它的改变映射到我们在主块中使用的x
的值。
用同样的global
语句可以指定多个全局变量,比如: global x, y, z
。
参数默认值
对于一些函数,你可能想要一些参数是可选,即在用户不希望为它们提供值时使用默认值,这在默认的参数值的帮助下完成的。你可以在函数定义中通过在参数名称后使用赋值操作符(=
)后跟默认值来指定默认的参数值。
注意,默认参数值应该是一个常数。更准确的说,默认的参数值应该是不可变的——这在后面的章节中做了详细解释。现在,只要记住这点。
例子 (保存为 func_default.py):
def say(message, times = 1):
print(message * times)
say('你好')
say('世界', 5)
输出:
$ python3 func_default.py
你好
世界世界世界世界世界
它是如何工作的:
函数say
是用来按照指定的次数打印一个字符串。如果我们不提供一个值,那么在默认情况下字符串只打印一次。为此,我们为参数times
指定一个默认参数值1
。
在第一次使用函数say
时,我们只提供了字符串,它打印字符串一次。在第二次使用say
时,我们提供了字符串和一个实参5
两个参数,说明我们想要say
字符串5次。
重要提示 只有在参数列表后面的的参数可以被赋予默认参数值,即在参数列表中,你不能在没有默认值的参数前有有默认参数值的参数。 这是因为,值按位置分配给参数。例如,
def func(a, b=5)
是有效的,而def func(a=5, b)
是无效的。
参数关键字
如果你有一些有许多参数的函数,您想要指定参数中的一些,那么,你可以通过为参数命名来为它们赋值——这叫做参数关键字——我们使用名称(关键字)而不是位置(我们一直使用的)来指定函数的参数。
这有两个优势,一是,使用函数容易,因为我们不需要担心参数的顺序。二是,如果其他参数有默认参数值,我们可以只给我们想赋值的参数赋值。
例子 (保存为func_key.py):
def func(a, b=5, c=10):
print('a为', a, '和b为', b, '和c为', c)
func(3, 7)
func(25, c=24)
func(c=50, a=100)
输出:
$ python func_key.py
a为3 和b为7 和c为10
a为25 和b为5 和c为24
a为100 和b为5 和c为50
它是如何工作的:
名为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)
,我们为所有给定的值使用了参数关键字。注意,我们为参数c
指定值是在参数a
之前,尽管在函数定义中a
在c
前。
变量参数
有时你可能想定义一个函数,它可以获取参数的任何值,这可以通过使用星号(另存为total.py)实现:
def total(a=5, *numbers, **phonebook):
print('a', a)
#通过元组遍历全部的参数
for single_item in numbers:
print('single_item', single_item)
#通过字典遍历全部的参数
for first_part, second_part in phonebook.items():
print(first_part,second_part)
print(total(10,1,2,3,Jack=1123,John=2231,Inge=1560))
输出:
$ python function_varargs.py
a 10
single_item 1
single_item 2
single_item 3
Inge 1560
John 2231
Jack 1123
None
它是如何工作的:
当我们声明一个星号的参数,如*param
,那么从这一点开始到结束的所有位置的参数都被收集到一个叫param的元组中。
同样,当我们声明一个双星参数,如**param
,那么人那一点开始到结束的所有关键字参数都被收集到一个叫param的字典中。
我们将在数据结构中探讨元组和字典。
return语句
return 语句用来从函数中return(返回),也就是说跳出函数。同样,我们也可以从函数中选择性地返回一个值。
例子 (保存为func_return.py):
def maximum(x, y):
if x > y:
return x
elif x == y:
return '两个数相等'
else:
return y
print(maximum(2, 3))
输出:
$ python func_return.py
3
它是如何工作的:
函数maximum
返回参数中的最大值,在这个例子中是提供给函数的数值。它使用了简单的if..else
语句找到比较大的值,然后返回那个值。
注意,没有一个值的return
语句相当于return None
(什么也不返回)。None
是Python中的一个特殊类型,它代表什么也没有。例如,如果一个变量的值是None
,它说明这个变量没有值。
除非你已经写了自己的return
语句,否则,每个函数都默认包含一个return None
语句。通过运行print(someFunction())
你可以看到这一点,这里someFunction
没有使用return
语句,比如:
def someFunction():
pass
在Python中pass语句用来说明一个空的语句块。
提示:已经有一个叫
max
的内建函数能够完成'find maximum'函数的功能 ,因此,只要可能使用这个内建函数。
文档字符串
Python有一个叫文档字符串的好特性,通常用缩写名docstrings来指定。 文档字符串是你应该使用的一个重要工具,它对程序文档有助,令其容易理解。令人惊讶的是,当程序实际运行时,我们甚至可以从例如一个函数返回文档字符串。
例子 (保存为func_doc.py):
def printMax(x, y):
'''打印两个数中的最大值。
两个值必须是整数。'''
# 如果可能,转换为整数
x = int(x)
y = int(y)
if x > y:
print(x, '最大')
else:
print(y, '最大')
printMax(3, 5)
print(printMax.__doc__)
输出:
$ python func_doc.py
5 最大
打印两个数中的最大值。
两个值必须是整数。
它是如何工作的:
函数的第一个逻辑行的字符串是那个函数的文档字符串。注意,文档字符串也适用于在后面的章节将要学习的模块和类。
文档的贯例是多行字符串,第一行以大写字母开头以句点(.)结束(注:可以使用中文),第二行是空行,从第三行开始是详细描述。强烈建议,为你重要的函数写文档字符串要遵循此贯例。
我们可以使用printMax
函数的__doc__
(注意,双下划线)属性(属于名字的)访问printMax函数的文档字符串。只要记住,Python把一切事物作为一个对象对待,这也包括函数。我们将在类这一章学习关于对象的更多知识。
如果你在Python中已经使用过help()
,那么你已经看到如何使用文档字符串了!它所做的仅仅是获取函数的 __doc__
属性,并以一个整洁的方式显示给你。你可以在上面的函数——在你的程序中仅包括help(printMax)
尝试一下。记得按下q
键,退出help
。
自动化工具可以从你的程序中以这种方式检索文档。因此,我强烈建议,为你写的任何重要函数使用文档字符串。来自Python的自动化工具pydoc
命令使用文档字符串的工作原理类似于help()
。
小结
我们已经见过函数的很多方面,但请注意,我们仍然没有覆盖它们的所有方面。然而,我们已经覆盖了Python函数日常使用的大部分。
接下来,我们将看到如何创建及使用Python模块。