# 函数
函数是可重用的程序片段。它允许你给一个代码块起一个名字,使用这个名字,你可以在程序的任何地方运行任何次数。这就是所谓的函数**调用**。我们已经使用了许多内置函数, 如`len`和`range`。
在任何有实际使用价值的软件中,函数的概念都是**最**重要的基石(对于任何编程语言都一样)。所以,在这一章我们将探索函数的方方面面。
定义函数使用`def`关键字。在这个**关键字**之后是**标识**函数的名字,之后是在一对括号中附上一些变量名,最后在行的末尾是冒号。接下来是代码块--函数函数体。我们用一个简单地例子看一下怎样定义一个函数:
例子 (保存为function1.py):
```python
def sayHello():
# 函数的代码块
print('世界您好!')
# 函数在此结束
sayHello() # 调用函数
sayHello() # 再次调用函数
```
输出:
```shell
C:\> python function1.py
世界您好!
世界您好!
```
**它是如何工作的:**
我们使用上述的语法,定义了一个名为`sayHello`的函数。这个函数没有参数,因此没有在圆括号中声明变量。函数的参数用来输入数据到函数中,以便我们可以给它传递不同的值,返回不同的结果。
注意,我们可以调用相同的函数两次,这意味着我们不需要再写两次同样的代码。
## 函数的参数
一个函数可以带参数--你可以在调用的时候给参数赋值,这样函数就可以使用这些参数进行处理。这些参数就像变量,所不同的是当我们调用函数时这些变量的值才会被定义,当函数运行时,它们已经有了指定的的值。
我们在定义函数的时候定义参数,写在一对括号中,之间用逗号分隔。当我们调用这个函数的时候,我们以同样的方式提供这些值。注意我们使用的术语——在函数的定义中给出的名字叫**形参**,而在函数调用时您提供的值被称为**实参**。
例子 (保存为function_param.py):
```python
def print_max(a, b):
if a > b:
print(a, '大')
elif a == b:
print(a, '等于', b)
else:
print(b, '大')
# 直接给出字面值
print_max(3, 4)
x = 5
y = 7
# 变量作为参数
print_max(x, y)
```
输出:
```
C:\> python function_param.py
4 大
7 大
```
**它如何工作的:**
在这里,我们定义了一个名为`print_max`的函数,它有`a`和`b`两个参数。我们使用简单的`if..else`语句找出比较大的数,然后打印较大的数。
我们第一次调用函数`print_max`,我们直接提供了数字作为参数。第二次调用的时候,我们使用变量作为参数。`print_max(x, y)`把实参`x`分配给形参`a`,`y`分配给`b`。在这两种情况下,`print_max`函数以同样方式工作。
## 局部变量
你在函数定义中声明的变量,与在函数外使用的其它同名变量没有任何关系,即变量名称对函数来说是**局部**的。这叫变量的**作用域**。所有变量的作用域,都是从他们在代码块中被定义开始,一直到代码块结束为止。
例子 (保存为function_local.py):
```python
x = 50
def func(x):
print('x等于', x)
x = 2
print('局部变量x改为', x)
func(x)
print('x仍然是', x)
```
输出:
```bash
C:\> python function_local.py
x等于50
局部变量x改变为2
x仍然是50
```
**它是如何工作的:**
第一次我们输出的时候,我们在函数体的第一行打印变量**x**的**值**,Python使用在主程序中定义的的值,代入到实参中完成输出。
接下来,我们给`x`赋值为`2`,变量`x`是函数的局部变量,因此在函数中当我们改变`x`的值时,在主程序中定义的变量`x`不受影响。
最后在主程序中调用`print`函数,显示输出在主程序中定义的变量`x`,说明在函数中修改局部变量的值对主程序的变量没有影响。
## 使用全局声明
在函数体内部,如果你想给在主程序中(即未在任何函数或类之中)定义的变量赋值,那么你必须告诉Python,变量不是局部的,而是**全局**的。我们使用`global`语句,没有`global`语句赋值给一个在函数外定义的变量是不可能的。
如果在函数体内部没有同名的变量,您也可以不使用`global`而直接使用这些在函数外定义的变量的值。然而,我们并不鼓励这样做,因为对于程序的读者来说,他会不清楚变量是在哪里定义的。使用 `global` 语句就非常清楚,变量定义在主程序中。
例子 (保存为function_global.py):
```python
x = 50
def func():
global x
print('x的值是', x)
x = 2
print('全局变量x改为', x)
func()
print('x的值是', x)
```
输出:
```shell
C:\> python function_global.py
x的值是50
全局变量to改为2
x的值是2
```
**它是如何工作的:**
`global`语句用来声明`x`是全局变量,当我们在函数内给`x`赋值时,它直接改变我们在主程序中使用的`x`的值。
用一个的`global`语句可以指定多个全局变量,比如: `global x, y, z`。
## 参数默认值
对于一些函数,你可能需要一些参数是**可选**,即在用户不希望为它们提供值时使用默认值。在Python中我们可以为函数的参数指定默认的参数值。在函数定义中通过在参数名称后使用赋值运算符(`=`)后跟默认值来指定默认的参数值。
注意,默认参数值应该是一个常数。更准确的说,默认的参数值应该是不可变的——关于这一点在后面的章节中会有更详细的解释。现在,只要记住这点。
例子 (保存为 function_default.py):
```python
def say(message, times = 1):
print(message * times)
say('你好')
say('世界', 5)
```
输出:
```
$ python3 function_default.py
你好
世界世界世界世界世界
```
**它是如何工作的:**
函数`say`是用来按照指定的次数打印一个字符串。如果我们不提供一个值,那么在默认情况下字符串只打印一次。为此,我们为参数`times`指定一个默认参数值`1`。
在第一次使用函数`say`时,我们只提供了字符串,它打印字符串一次。在第二次使用`say`时,我们提供了字符串和一个数字`5`两个参数,说明我们想要`say`字符串打印5次。
> **重要提示**
>
> 默认参数值只能放在参数列表的最后。即在参数列表中,你不能在没有默认值的参数前有带默认参数值的参数。
>
> 这是因为,Python按照位置把值分配给参数。例如,`def func(a, b=5)`是有效的,而`def func(a=5, b)`是**无效**的。
## 参数关键字
如果你的函数有很多参数,在调用的时候您想给其中一部分参数赋值,那么你可以通过为参数命名来为它们赋值,这叫做**参数关键字**。我们使用名称(关键字)而不是位置(我们一直使用的)来指定函数的参数。
这有两个优势:一是,可以更自由的使用函数,因为我们不需要担心参数的顺序;二是,如果其他参数有默认值,我们可以只给我们想赋值的参数赋值。
例子 (保存为function_keyword.py):
```python
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 function_keyword.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`前。
## 可变参数
有时你可能想定义一个函数,它可以获取任意数量的参数,这可以通过使用星号(保存为function_varargs.py)实现:
```python
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('-----')
print(first_part, second_part)
print(total(10, 1, 2, 3, Jack=1123, John=2231, Inge=1560))
```
输出:
```shell
C:\> 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`的字典中。
我们将在[数据结构](data_structures.md)中探讨元组和字典。
## return语句
return 语句用来从函数中**return(返回)**,也就是说跳出函数。同样,我们也可以从函数中选择性地**返回一个值**。
例子 (保存为function_return.py):
```python
def maximum(x, y):
if x > y:
return x
elif x == y:
return '两个数相等'
else:
return y
print(maximum(2, 3))
```
输出:
```
C:\> python function_return.py
3
```
**它是如何工作的:**
函数`maximum`返回参数中的最大值,在这个例子中我们提供给函数的参数是两个数字。它使用了简单的`if..else`语句找到比较大的值,然后**返回**那个值。
注意,没有返回值的`return`语句相当于`return None`(什么也不返回)。`None`是Python中的一个特殊类型,它代表什么也没有。例如,如果一个变量的值是`None`,它说明这个变量没有值。
除非你已经写了自己的`return`语句,否则,每个函数在末尾都默认包含一个`return None`语句。通过运行`print(someFunction())`你可以看到这一点,这里`someFunction` 没有使用`return`语句,比如:
```python
def someFunction():
pass
```
在Python中pass语句用来说明一个空的代码块。
> 提示:已经有一个叫`max`的内建函数能够完成'find maximum'函数的功能 ,因此,我们还是尽可能使用内建函数。
## 文档字符串
Python有一个叫**文档字符串(docstrings)**的好特性。文档字符串是你应该使用的一个重要工具,它可以帮助你给程序补充文档信息,令其容易理解。Python还有一个令人惊叹的特性,当程序运行的时候,我们可以从函数中获取文档字符串。
例子 (保存为function_docstring.py):
```python
def print_max(x, y):
'''打印两个数中的最大值。
两个值必须是整数。'''
# 如果可能,转换为整数
x = int(x)
y = int(y)
if x > y:
print(x, '最大')
else:
print(y, '最大')
print_max(3, 5)
print(print_max.__doc__)
```
输出:
```shell
C:\> python function_docstring.py
5 最大
打印两个数中的最大值。
两个值必须是整数。
```
**它是如何工作的:**
函数的第一个逻辑行的字符串是那个函数的**文档字符串**。注意,文档字符串也适用于在后面的章节将要学习的[模块](modules.md)和[类](oop.md)。
通常情况下,文档字符串有多行,第一行紧挨着`'''`,并且以句号(。)结束。第二行是空行,从第三行开始是详细描述。**强烈建议**,为所有重要的函数写文档字符串都要遵循此贯例。
我们可以使用`print_max`函数的`__doc__`(注意,**双下划线**)属性访问print_max函数的文档字符串。只要记住,Python把**一切事物**当做对象看待,这也包括函数。我们将在[类](oop.md)这一章学习关于对象的更多知识。
如果你在Python中已经使用过`help()`,那么你已经看到如何使用文档字符串了!它所做的仅仅是获取函数的 `__doc__` 属性,并以一个整洁的方式显示给你。你可以试一下上面的函数——在你的程序中增加一行`help(print_max)`尝试一下。
自动化工具可以从你的程序中以这种方式检索文档。因此,我**强烈建议**,为你写的任何重要函数书写文档字符串。来自Python的自动化工具`pydoc`使用文档字符串的工作原理类似于`help()`。
## 小结
我们已经了解了函数的方方面面,但请注意,我们仍然没有覆盖关于函数的全部内容。不过我们已经涵盖了Python函数日常使用的大部分内容。
接下来,我们将看到如何创建及使用Python模块。
- 开始学习
- 搭建Python开发环境
- 简明Python教程
- 致敬
- 前言
- 关于Python
- 安装
- 第一步
- 基础
- 运算符和表达式
- 控制流
- 函数
- 模块
- 数据结构
- 实战案例
- 面向对象编程
- 输入与输出
- 异常处理
- 标准库
- 更多
- 继续学习
- 附录:免费/自由和开放源码软件
- 附录: 关于
- 附录: 版本历史
- 附录: 翻译
- 附录: 参与翻译工作
- 反馈
- Django Step Sy Step
- 第一讲 从简单到复杂
- 第二讲 做加法的例子
- 第三讲 使用Template
- 第四讲 生成csv格式文件
- 第五讲 session示例
- 第六讲 wiki的例子
- 第七讲 通讯录的例子
- 第八讲 文件导入和导出
- 第九讲 通讯录的美化
- 第十讲 扩展django的模板
- 第十一讲 用户管理
- 第十二讲 搜索和部署
- 第十三讲 Ajax的实现(一)
- 第十四讲 Ajax的实现(二)
- 第十五讲 i18n的一个简单实现
- 第十六讲 自定义Calendar Tag
- 第十七讲 View,Template和Tag
- Django开发实战
- Python开发规范
- Django项目的gitignore
- 怎样配置开发环境的settings
- 如何使用Django和Vue.js构建项目
- 使用WebSocket开发网页聊天室
- 怎样使Django Admin显示中文
- 怎样使Model在Admin界面中显示中文
- 使用Django Admin怎样上传并显示图片
- 解决Django模板和Vue指令花括号冲突的问题
- 使用Django和Vue开发微信公众号
- 使用Django和Vue调用微信JSSDK开发微信支付