目标

  • 函数的快速体验
  • 函数的基本使用
  • 函数的参数
  • 函数的返回值
  • 函数的嵌套调用
  • 在模块中定义函数

    01. 函数的快速体验

    1.1 快速体验

  • 所谓函数,就是把具有独立功能的代码块组织为一个小模块,在需要的时候调用

  • 函数的使用包含两个步骤:
    1. 定义函数 —— 封装 独立的功能
    2. 调用函数 —— 享受 封装 的成果
  • 函数的作用,在开发程序时,使用函数可以提高编写的效率以及代码的重用

    02. 函数基本使用

    2.1 函数的定义

    定义函数的格式如下:

    1. def 函数名():
    2. 函数封装的代码
    3. ……
  1. def是英文define的缩写
  2. 函数名称应该能够表达函数封装代码的功能,方便后续的调用
  3. 函数名称的命名应该符合标识符的命名规则
    • 可以由 字母下划线数字 组成
    • 不能以数字开头
    • 不能与关键字重名

      2.2 函数调用

      调用函数很简单的,通过函数名()即可完成对函数的调用

      2.3 第一个函数演练

      需求
  • \1. 编写一个打招呼 say_hello 的函数,封装三行打招呼的代码
  • \2. 在函数下方调用打招呼的代码 ```python name = “小明”

解释器知道这里定义了一个函数

def say_hello(): print(“hello 1”) print(“hello 2”) print(“hello 3”)

print(name)

只有在调用函数时,之前定义的函数才会被执行

函数执行完成之后,会重新回到之前的程序中,继续执行后续的代码

say_hello()

print(name)

  1. 用**单步执行 F8 F7**观察以下代码的执行过程
  2. - 定义好函数之后,只表示这个函数封装了一段代码而已
  3. - 如果不主动调用函数,函数是不会主动执行的
  4. <a name="aQGr0"></a>
  5. #### 思考
  6. - 能否将**函数调用**放在**函数定义**的上方?
  7. - 不能!
  8. - 因为在 **使用函数名** 调用函数之前,必须要保证 Python 已经知道函数的存在
  9. - 否则控制台会提示 NameError: name 'say_hello' is not defined (**名称错误:say_hello 这个名字没有被定义**)
  10. <a name="C9hX3"></a>
  11. ### 2.4 函数的文档注释
  12. - 在开发中,如果希望给函数添加注释,应该在 **定义函数** 的下方,使用 **连续的三对引号**
  13. - **连续的三对引号** 之间编写对函数的说明文字
  14. - **函数调用** 位置,使用快捷键 CTRL + Q 可以查看函数的说明信息
  15. 注意:因为**函数体相对比较独立**,**函数定义的上方**,应该和其他代码(包括注释)保留**两个空行**
  16. <a name="OwRKG"></a>
  17. ## 03. 函数的参数
  18. **演练需求**
  19. 1. 开发一个 sum_2_num 的函数
  20. 1. 函数能够实现 **两个数字的求和** 功能
  21. 演练代码如下:
  22. ```python
  23. def sum_2_num():
  24. num1 = 10
  25. num2 = 20
  26. result = num1 + num2
  27. print("%d + %d = %d" % (num1, num2, result))
  28. sum_2_num()

思考一下存在什么问题
函数只能处理固定数值的相加
如何解决?

  • 如果能够把需要计算的数字,在调用函数时,传递到函数内部就好了!

    3.1 函数参数的使用

  • 在函数名的后面的小括号内部填写 参数

  • 多个参数之间使用 , 分隔 ```python def sum_2_num(num1, num2):

    result = num1 + num2

    print(“%d + %d = %d” % (num1, num2, result))

sum_2_num(50, 20)

  1. <a name="ZDimm"></a>
  2. ### 3.2 参数的作用
  3. - **函数**,把**具有独立功能的代码块**组织为一个小模块,在需要的时候**调用**
  4. - 函数的参数,增加函数的通用性,针对相同的数据处理逻辑,能够适应更多的数据
  5. 1. 在函数 **内部**,把参数当做 **变量** 使用,进行需要的数据处理
  6. 1. 函数调用时,按照函数定义的**参数顺序**,把 **希望在函数内部处理的数据**,**通过参数** 传递
  7. <a name="pmi53"></a>
  8. ### 3.3 形参和实参
  9. - **形参**:**定义** 函数时,小括号中的参数,是用来接收参数用的,在函数内部 **作为变量使用**
  10. - **实参**:**调用** 函数时,小括号中的参数,是用来把数据传递到 **函数内部** 用的
  11. <a name="ntdbA"></a>
  12. ## 04. 函数的返回值
  13. - 在程序开发中,有时候,会希望 **一个函数执行结束后,告诉调用者一个结果**,以便调用者针对具体的结果做后续的处理
  14. - **返回值** 是函数 **完成工作**后,**最后** 给调用者的 **一个结果**
  15. - 在函数中使用 return 关键字可以返回结果
  16. - 调用函数一方,可以 **使用变量** 来 **接收** 函数的返回结果
  17. 注意:return表示返回,后续的代码都不会被执行
  18. ```python
  19. def sum_2_num(num1, num2):
  20. """对两个数字的求和"""
  21. return num1 + num2
  22. # 调用函数,并使用 result 变量接收计算结果
  23. result = sum_2_num(10, 20)
  24. print("计算结果是 %d" % result)

05. 函数的嵌套调用

  • 一个函数里面又调用另外一个函数,这就是函数嵌套调用
  • 如果函数 test2中,调用了另外一个函数test1

    • 那么执行到调用 test1 函数时,会先把函数 test1 中的任务都执行完
    • 才会回到 test2 中调用函数 test1 的位置,继续执行后续的代码 ```python def test1():

      print(“ 50) print(“test 1”) print(“ 50)

def test2():

  1. print("-" * 50)
  2. print("test 2")
  3. test1()
  4. print("-" * 50)

test2()

  1. <a name="rZtC6"></a>
  2. ### 函数嵌套的演练 —— 打印分隔线python
  3. 体会一下工作中**需求是多变**的<br />**需求 1**
  4. - 定义一个 print_line 函数能够打印 * 组成的 **一条分隔线**
  5. ```python
  6. def print_line(char):
  7. print("*" * 50)

需求 2

  • 定义一个函数能够打印 由任意字符组成 的分隔线 ```python def print_line(char):

    print(char * 50)

  1. **需求 3**
  2. - 定义一个函数能够打印 **任意重复次数** 的分隔线
  3. ```python
  4. def print_line(char, times):
  5. print(char * times)

print 和 return 是一样的道理,用return的话 需要定义一个变量来接收。
需求 4

  • 定义一个函数能够打印 5 行 的分隔线,分隔线要求符合需求 3

提示:工作中针对需求的变化,应该冷静思考,不要轻易修改之前已经完成的,能够正常执行的函数

  1. def print_line(char, times):
  2. print(char * times)
  3. def print_lines(char, times):
  4. row = 0
  5. while row < 5:
  6. print_line(char, times)
  7. row += 1

06. 使用模块中的函数

模块是 Python 程序架构的一个核心概念

  • 模块 就好比是 工具包,要想使用这个工具包中的工具,就需要 导入 import 这个模块
  • 每一个以扩展名 py 结尾的 Python 源代码文件都是一个 模块
  • 在模块中定义的 全局变量函数 都是模块能够提供给外界直接使用的工具

    6.1 第一个模块体验

    步骤

  • 新建lx_分隔线模块.py

    • 复制 `lx_打印多条分隔线.py 中的内容,最后一行 print 代码除外
    • 增加一个字符串变量
  • 新建 lx体验模块.py 文件,并且编写以下代码: ```python import lx分隔线模块

lx分隔线模块.print_line(“-“, 80) print(lx分隔线模块.name)

  1. <a name="AJvXg"></a>
  2. #### 体验小结
  3. - 可以 **在一个 Python 文件** 中 **定义 变量 或者 函数**
  4. - 然后在 **另外一个文件中** 使用 import 导入这个模块
  5. - 导入之后,就可以使用 模块名.变量 / 模块名.函数 的方式,使用这个模块中定义的变量或者函数
  6. **模块**可以让**曾经编写过的代码**方便的被**复用**!
  7. **函数进阶**
  8. <a name="p1SG7"></a>
  9. ## 目标
  10. - 变量的引用
  11. - 可变和不可变类型
  12. - 局部变量和全局变量
  13. - 匿名函数
  14. <a name="aYrKU"></a>
  15. ## 01. 变量的引用
  16. - 变量 和 数据 都是保存在 **内存** 中的
  17. - 在 Python 中 **函数 的 参数传递** 以及 **返回值** 都是靠 **引用** 传递的
  18. <a name="UbqrE"></a>
  19. ### 1.1 引用的概念
  20. 在Python中
  21. - **变量** 和 **数据** 是分开存储的
  22. - **数据** 保存在内存中的一个位置
  23. - **变量** 中保存着数据在内存中的地址
  24. - **变量** 中 **记录数据的地址**,就叫做 **引用**
  25. - 使用 id() 函数可以查看变量中保存数据所在的 **内存地址**
  26. 注意:如果变量已经被定义,当给一个变量赋值的时候,本质上是**修改了数据的引用**
  27. - 变量 **不再** 对之前的数据引用
  28. - 变量 **改为** 对新赋值的数据引用
  29. <a name="UZJl4"></a>
  30. ### 1.2 变量引用 的示例
  31. 在Python中,变量的名字类似于**便签纸**贴在**数据**上
  32. - 定义一个整数变量 a,并且赋值为 1
  33. - ![](https://cdn.nlark.com/yuque/0/2021/png/21397054/1618570628611-d51165c2-a3eb-4217-adbc-29c82ac90b60.png#from=url&id=TrmD4&margin=%5Bobject%20Object%5D&originHeight=370&originWidth=404&originalType=binary&ratio=1&status=done&style=none)
  34. - 将变量 a 赋值为 2
  35. - ![](https://cdn.nlark.com/yuque/0/2021/png/21397054/1618570649034-521ed558-4a83-4899-97e5-5b3099342860.png#from=url&id=p8FKg&margin=%5Bobject%20Object%5D&originHeight=331&originWidth=543&originalType=binary&ratio=1&status=done&style=none)
  36. - 定义一个整数变量 b,并且将变量 a 的值赋值给 b
  37. - ![](https://cdn.nlark.com/yuque/0/2021/png/21397054/1618570674849-d323916f-88d2-4c6a-bef5-2974dfa11549.png#from=url&id=CPrxX&margin=%5Bobject%20Object%5D&originHeight=355&originWidth=588&originalType=binary&ratio=1&status=done&style=none)
  38. <a name="GgLa8"></a>
  39. ### 1.3 函数的参数和返回值的传递
  40. 在Python中,函数的**实参**/**返回值**都是是靠**引用**来传递来的
  41. ```python
  42. def test(num):
  43. print("-" * 50)
  44. print("%d 在函数内的内存地址是 %x" % (num, id(num)))
  45. result = 100
  46. print("返回值 %d 在内存中的地址是 %x" % (result, id(result)))
  47. print("-" * 50)
  48. return result
  49. a = 10
  50. print("调用函数前 内存地址是 %x" % id(a))
  51. r = test(a)
  52. print("调用函数后 实参内存地址是 %x" % id(a))
  53. print("调用函数后 返回值内存地址是 %x" % id(r))

02. 可变和不可变类型

  • 不可变类型,内存中的数据不允许被修改:
    • 数字类型 int, bool, float, complex, long(2.x)
    • 字符串 str
    • 元组 tuple
  • 可变类型,内存中的数据可以被修改:

    • 列表 list
    • 字典 dict

    注意

  1. 可变类型的数据变化,是通过方法来实现的
  2. 如果给一个可变类型的变量,赋值了一个新的数据,引用会修改
    • 变量 不再 对之前的数据引用
    • 变量 改为 对新赋值的数据引用

      03. 局部变量和全局变量

  • 局部变量 是在 函数内部 定义的变量,只能在函数内部使用
  • 全局变量 是在 函数外部定义 的变量(没有定义在某一个函数内),所有函数 内部 都可以使用这个变量

提示:在其他的开发语言中,大多不推荐使用全局变量—— 可变范围太大,导致程序不好维护!

3.1 局部变量

  • 局部变量 是在 函数内部 定义的变量,只能在函数内部使用
  • 函数执行结束后,函数内部的局部变量,会被系统回收
  • 不同的函数,可以定义相同的名字的局部变量,但是 彼此之间 不会产生影响

    局部变量的作用

  • 在函数内部使用,临时 保存 函数内部需要使用的数据 ```python def demo1():

    num = 10

    print(num)

    num = 20

    print(“修改后 %d” % num)

def demo2():

  1. num = 100
  2. print(num)

demo1() demo2()

print(“over”)

  1. **注意**:函数执行时,**需要处理变量时**会:
  2. 1. **首先** 查找 **函数内部** 是否存在 **指定名称 的局部变量**,**如果有,直接使用**
  3. 1. 如果没有,查找 **函数外部** 是否存在 **指定名称 的全局变量**,**如果有,直接使用**
  4. 1. 如果还没有,程序报错!
  5. <a name="asAtP"></a>
  6. #### 1) 函数不能直接修改 全局变量的引用
  7. - **全局变量** 是在 **函数外部定义** 的变量(没有定义在某一个函数内),**所有函数** 内部 **都可以使用这个变量**
  8. 提示:在其他的开发语言中,大多**不推荐使用全局变量**—— 可变范围太大,导致程序不好维护!
  9. - 在函数内部,可以 **通过全局变量的引用获取对应的数据**
  10. - 但是,**不允许直接修改全局变量的引用** —— 使用赋值语句修改全局变量的值
  11. ```python
  12. num = 10
  13. def demo1():
  14. print("demo1" + "-" * 50)
  15. # 只是定义了一个局部变量,不会修改到全局变量,只是变量名相同而已
  16. num = 100
  17. print(num)
  18. def demo2():
  19. print("demo2" + "-" * 50)
  20. print(num)
  21. demo1()
  22. demo2()
  23. print("over")

注意:只是在函数内部定义了一个局部变量而已,只是变量名相同 —— 在函数内部不能直接修改全局变量的值

2) 在函数内部修改全局变量的值

  • 如果在函数中需要修改全局变量,需要使用 global 进行声明 ```python num = 10

def demo1():

  1. print("demo1" + "-" * 50)
  2. # global 关键字,告诉 Python 解释器 num 是一个全局变量
  3. global num
  4. # 只是定义了一个局部变量,不会修改到全局变量,只是变量名相同而已
  5. num = 100
  6. print(num)

def demo2():

  1. print("demo2" + "-" * 50)
  2. print(num)

demo1() demo2()

print(“over”)

  1. <a name="tgThW"></a>
  2. #### 3) 全局变量定义的位置
  3. - 为了保证所有的函数都能够正确使用到全局变量,应该 **将全局变量定义在其他函数的上方**
  4. ```python
  5. a = 10
  6. def demo():
  7. print("%d" % a)
  8. print("%d" % b)
  9. print("%d" % c)
  10. b = 20
  11. demo()
  12. c = 30

注意

  • 由于全局变量 c,是在调用函数之后,才定义的,在执行函数时,变量还没有定义,所以程序会报错!

    4) 全局变量命名的建议

  • 为了避免局部变量和全局变量出现混淆,在定义全局变量时,有些公司会有一些开发要求,例如:

  • 全局变量名前应该增加 g 或者 gl 的前缀

提示:具体的要求格式,各公司要求可能会有些差异

04.函数参数和返回值的作用

函数根据 有没有参数 以及 有没有返回值,可以 相互组合,一共有 4 种 组合形式

  1. 无参数,无返回值
  2. 无参数,有返回值
  3. 有参数,无返回值
  4. 有参数,有返回值

函数基础,函数进阶 - 图1
定义函数时,是否接收参数,或者是否返回结果,是根据 实际的功能需求 来决定的!

  1. 如果函数 内部处理的数据不确定,就可以将外界的数据以参数传递到函数内部
  2. 如果希望一个函数 执行完成后,向外界汇报执行结果,就可以增加函数的返回值

    1.1 无参数,无返回值

    此类函数,不接收参数,也没有返回值,应用场景如下:

  3. 只是单纯地做一件事情,例如 显示菜单

  4. 在函数内部 针对全局变量进行操作,例如:新建名片,最终结果 记录在全局变量

注意:

  • 如果全局变量的数据类型是一个 可变类型,在函数内部可以使用 方法 修改全局变量的内容 —— 变量的引用不会改变
  • 在函数内部,使用赋值语句 才会 修改变量的引用

    1.2 无参数,有返回值

    此类函数,不接收参数,但是有返回值,应用场景如下:

  • 采集数据,例如 温度计,返回结果就是当前的温度,而不需要传递任何的参数

    1.3 有参数,无返回值

    此类函数,接收参数,没有返回值,应用场景如下:

  • 函数内部的代码保持不变,针对 不同的参数 处理 不同的数据

  • 例如 名片管理系统 针对 找到的名片修改删除 操作

    1.4 有参数,有返回值

    此类函数,接收参数,同时有返回值,应用场景如下:

  • 函数内部的代码保持不变,针对 不同的参数 处理 不同的数据,并且 返回期望的处理结果

  • 例如名片管理系统使用字典默认值和提示信息提示用户输入内容

    • 如果输入,返回输入内容
    • 如果没有输入,返回字典默认值

      05. 函数的返回值 进阶

  • 在程序开发中,有时候,会希望 一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理

  • 返回值 是函数 完成工作后,最后 给调用者的 一个结果
  • 在函数中使用 return 关键字可以返回结果
  • 调用函数一方,可以 使用变量接收 函数的返回结果

问题:一个函数执行后能否返回多个结果?

示例 —— 温度和湿度测量

  • 假设要开发一个函数能够同时返回当前的温度和湿度
  • 先完成返回温度的功能如下: ```python def measure(): “””返回当前的温度”””

    print(“开始测量…”) temp = 39 print(“测量结束…”)

    return temp

result = measure() print(result)

  1. - 在利用 **元组** 在返回温度的同时,也能够返回 **湿度**
  2. - 改造如下:
  3. ```python
  4. def measure():
  5. """返回当前的温度"""
  6. print("开始测量...")
  7. temp = 39
  8. wetness = 10
  9. print("测量结束...")
  10. return (temp, wetness)

提示:如果一个函数返回的是元组,括号可以省略
技巧

  • 在 Python 中,可以 将一个元组 使用 赋值语句 同时赋值给 多个变量
  • 注意:变量的数量需要和元组中的元素数量保持一致
  • result = temp, wetness = measure()

    面试题 —— 交换两个数字

    题目要求
  1. 有两个整数变量 a = 6, b = 100
  2. 不使用其他变量,交换两个变量的值

    解法 1 —— 使用其他变量

    1. # 解法 1 - 使用临时变量
    2. c = b
    3. b = a
    4. a = c

    解法 2 —— 不使用临时变量

    1. # 解法 2 - 不使用临时变量
    2. a = a + b
    3. b = a - b
    4. a = a - b

    解法 3 —— Python 专有,利用元组

    1. a, b = b, a

    06. 函数的参数 进阶

    1. 不可变和可变的参数

    问题 1:在函数内部,针对参数使用 赋值语句,会不会影响调用函数时传递的 实参变量? —— 不会!
  • 无论传递的参数是可变还是不可变

    • 只要 针对参数 使用 赋值语句,会在 函数内部 修改 局部变量的引用不会影响到 外部变量的引用 ```python def demo(num, num_list):

      print(“函数内部”)

      赋值语句

      num = 200 num_list = [1, 2, 3]

      print(num) print(num_list)

      print(“函数代码完成”)

gl_num = 99 gl_list = [4, 5, 6] demo(gl_num, gl_list) print(gl_num) print(gl_list)

  1. 问题 2:如果传递的参数是 **可变类型**,在函数内部,使用 **方法** 修改了数据的内容,**同样会影响到外部的数据**
  2. ```python
  3. def mutable(num_list):
  4. # num_list = [1, 2, 3]
  5. num_list.extend([1, 2, 3])
  6. print(num_list)
  7. gl_list = [6, 7, 8]
  8. mutable(gl_list)
  9. print(gl_list)

面试题 —— +=

  • 在 python 中,列表变量调用 += 本质上是在执行列表变量的 extend 方法,不会修改变量的引用 ```python def demo(num, num_list):

    print(“函数内部代码”)

    num = num + num

    num += num

    num_list.extend(num_list) 由于是调用方法,所以不会修改变量的引用

    函数执行结束后,外部数据同样会发生变化

    num_list += num_list

    print(num) print(num_list) print(“函数代码完成”)

gl_num = 9 gl_list = [1, 2, 3] demo(gl_num, gl_list) print(gl_num) print(gl_list)

  1. <a name="WJhgV"></a>
  2. ### 2 缺省参数
  3. - 定义函数时,可以给 **某个参数** 指定一个**默认值**,具有默认值的参数就叫做 **缺省参数**
  4. - 调用函数时,如果没有传入 **缺省参数** 的值,则在函数内部使用定义函数时指定的 **参数默认值**
  5. - 函数的缺省参数,**将常见的值设置为参数的缺省值**,从而 **简化函数的调用**
  6. - 例如:对列表排序的方法
  7. ```python
  8. gl_num_list = [6, 3, 9]
  9. # 默认就是升序排序,因为这种应用需求更多
  10. gl_num_list.sort()
  11. print(gl_num_list)
  12. # 只有当需要降序排序时,才需要传递 `reverse` 参数
  13. gl_num_list.sort(reverse=True)
  14. print(gl_num_list)

指定函数的缺省参数

  • 在参数后使用赋值语句,可以指定参数的缺省值

    1. def print_info(name, gender=True):
    2. gender_text = "男生"
    3. if not gender:
    4. gender_text = "女生"
    5. print("%s 是 %s" % (name, gender_text))

    提示

  1. 缺省参数,需要使用 最常见的值 作为默认值!
  2. 如果一个参数的值 不能确定,则不应该设置默认值,具体的数值在调用函数时,由外界传递!
  3. 在调用参数时,比如 print_info()时候里面填的bool值是什么它就是什么(小明,False)它就是女生,如果(小明)后面不带False,它就默认是男生。

    缺省参数的注意事项

    1) 缺省参数的定义位置
  • 必须保证带有默认值的缺省参数在参数列表末尾
  • 所以,以下定义是错误的!

    1. def print_info(name, gender=True, title):

    2) 调用带有多个缺省参数的函数
  • 调用函数时,如果有 多个缺省参数需要指定参数名,这样解释器才能够知道参数的对应关系!

    3 多值参数(知道)

    定义支持多值参数的函数

  • 有时可能需要 一个函数 能够处理的参数 个数 是不确定的,这个时候,就可以使用 多值参数

  • python中有两种多值参数:
    • 参数名前增加 一个* 可以接收 元组
    • 参数名前增加 两个* 可以接收 字典
  • 一般在给多值参数命名时,习惯使用以下两个名字
    • args —— 存放 元组 参数,前面有一个
    • kwargs —— 存放 字典* 参数,前面有两个
  • args 是 arguments 的缩写,有变量的含义
  • kw 是 keyword 的缩写,kwargs 可以记忆 键值对参数 ```python def demo(num, args, *kwargs):

    print(num) print(args) print(kwargs)

demo(1, 2, 3, 4, 5, name=”小明”, age=18, gender=True)

  1. 提示:**多值参数** 的应用会经常出现在网络上一些大牛开发的框架中,知道多值参数,**有利于我们能够读懂大牛的代码**
  2. <a name="iP2nb"></a>
  3. #### 多值参数案例 —— 计算任意多个数字的和
  4. **需求**
  5. 1. 定义一个函数 sum_numbers,可以接收的 **任意多个整数**
  6. 1. 功能要求:将传递的 **所有数字累加** 并且返回累加结果
  7. ```python
  8. def sum_numbers(*args):
  9. num = 0
  10. # 遍历 args 元组顺序求和
  11. for n in args:
  12. num += n
  13. return num
  14. print(sum_numbers(1, 2, 3))

元组和字典的拆包(知道)

  • 在调用带有多值参数的函数时,如果希望:
    • 将一个 元组变量,直接传递给 args
    • 将一个 字典变量,直接传递给 kwargs
  • 就可以使用拆包,简化参数的传递,拆包的方式是:

    • 元组变量前,增加 一个*
    • 字典变量前,增加 两个* ```python def demo(args, *kwargs):

      print(args) print(kwargs)

需要将一个元组变量/字典变量传递给函数对应的参数

gl_nums = (1, 2, 3) gl_xiaoming = {“name”: “小明”, “age”: 18}

会把 gl_nums 和 gl_xiaoming 作为元组传递给 args

demo(gl_nums, gl_xiaoming)

demo(gl_nums, *gl_xiaoming)

  1. 我希望他传递给元祖*args,我就标上一个* 我希望他传递给字典**kwargs,我就加上两个*
  2. <a name="oW86Q"></a>
  3. ## 07. 函数的递归
  4. 函数调用自身的 **编程技巧** 称为递归
  5. <a name="mPWUx"></a>
  6. ### 1 递归函数的特点
  7. **特点**
  8. - 一个函数内部调用自己
  9. - 函数内部可以调用其他函数,当然在函数内部也可以调用自己
  10. **代码特点**
  11. 1. 函数内部的 **代码** 是相同的,只是针对 **参数** 不同,**处理的结果不同**
  12. 1. 当参数满足一个条件时,函数不再执行
  13. - **这个非常重要**,通常被称为递归的出口,否则 **会出现死循环**!
  14. 示例代码
  15. ```python
  16. def sum_numbers(num):
  17. print(num)
  18. # 递归的出口很重要,否则会出现死循环
  19. if num == 1:
  20. return
  21. sum_numbers(num - 1)
  22. sum_numbers(3)

函数基础,函数进阶 - 图2

2 递归案例 —— 计算数字累加

需求

  1. 定义一个函数 sum_numbers
  2. 能够接收一个 num 的整数参数
  3. 计算 1 + 2 + … num 的结果 ```python def sum_numbers(num):

    if num == 1:

    1. return 1

    假设 sum_numbers 能够完成 num - 1 的累加

    temp = sum_numbers(num - 1)

    函数内部的核心算法就是 两个数字的相加

    return num + temp

print(sum_numbers(2))

  1. ![](https://cdn.nlark.com/yuque/0/2021/png/21397054/1623302598428-8ec016ea-9e60-4098-84e8-49fbbce15a31.png#from=url&id=YBVBd&margin=%5Bobject%20Object%5D&originHeight=435&originWidth=1222&originalType=binary&ratio=1&status=done&style=none)<br />提示:递归是一个 **编程技巧**,初次接触递归会感觉有些吃力!在处理 **不确定的循环条件时**,格外的有用,例如:**遍历整个文件目录的结构**
  2. <a name="FH101"></a>
  3. ## 08.匿名函数
  4. python 使用 lambda 来创建匿名函数。<br />lambda这个名称来自于LISP,而LISP则是从lambda calculus(一种符号逻辑形式)取这个名称的。 Python中,lambda作为一个关键字,作为引入表达式的语法。想比较def函数,lambda是单一的表达式,而不是语句块!<br />**所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。**
  5. - lambda 只是一个表达式,函数体比 def 简单很多。
  6. - lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
  7. - lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  8. - 虽然lambda函数看起来只能写一行,却不等同于CC++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
  9. <a name="EnwaY"></a>
  10. ##### 语法
  11. lambda 函数的语法只包含一个语句,如下:
  12. ```python
  13. lambda [arg1 [,arg2,.....argn]]:expression
  14. # lambda 参数列表:return [表达式] 变量
  15. # 由于lambda返回的是函数对象(构建的是一个函数对象),所以需要定义一个变量去接收
  1. # 可写函数说明
  2. sum = lambda arg1, arg2: arg1 + arg2;
  3. # 调用sum函数
  4. print ("相加后的值为 : ", sum( 10, 20 )) # 相加后的值为 : 30
  5. print ("相加后的值为 : ", sum( 20, 20 )) # 相加后的值为 : 40
  1. def test(a,b,func):
  2. result = func(a,b)
  3. return result
  4. num = test(11,22,lambda x,y:x+y)
  5. print(num)

匿名函数优点

  • 使用Python写一些脚本时,使用lambda可以省去定义函数的过程,让代码更加精简。
  • 对于一些抽象的,不会被别的地方再重复使用的函数,有时候函数起个名字也是个难题,使用lambda不需要考虑命名的问题
  • 使用lambda在某些时候然后代码更容易理解