<Python的函数(2)>——《Python》

目录

1.函数执行过程

2.链式调用

3.嵌套调用

4.函数递归

4.1 递归的概念

4.2 递归的优点

4.3 递归的缺点

5. 参数默认值

6. 关键字参数

7. 小结


1.函数执行过程

  • 调用函数才会执行函数体代码. 不调用则不会执行.
  • 函数体执行结束(或者遇到 return 语句), 则回到函数调用位置, 继续往下执行.
def test():
    print("执行函数内部代码")
    print("执行函数内部代码")
    print("执行函数内部代码")
print("1111")
test()
print("2222")
test()
print("3333")
这个过程还可以使用 PyCharm 自带的调试器来观察:
  • 点击行号右侧的空白, 可以在代码中插入 断点
  • 右键, Debug, 可以按照调试模式执行代码. 每次执行到断点, 程序都会暂停下来.
  • 使用 Step Into (F7) 功能可以逐行执行代码.

2.链式调用

编程演示:
# 判定是否是奇数


def isOdd(num):
    if num % 2 == 0:
        return False
    else:
        return True


result = isOdd(10)
print(result)
实际上也可以简化写作    print(isOdd(10))

 

把一个函数的返回值 , 作为另一个函数的参数 , 这种操作称为 链式调用 .
def isOdd(num):
    if num % 2 == 0:
        return False
    else:
        return True


def add(x,y):
    return x+y


print(isOdd(add(6,1)))

这是一种比较常见的写法.

3.嵌套调用

函数内部还可以调用其他的函数 , 这个动作称为 " 嵌套调用 " .
def test():
    print("执行函数内部代码")
    print("执行函数内部代码")
    print("执行函数内部代码")
test 函数内部调用了 print 函数 , 这里就属于嵌套调用 .
一个函数里面可以嵌套调用任意多个函数 .
函数嵌套的过程是非常灵活的
def a():
    print("函数 a")
def b():
    print("函数 b")
    a()
def c():
    print("函数 c")
    b()
def d():
    print("函数 d")
    c()
d()
如果把代码稍微调整, 打印结果则可能发生很大变化.
def a():
    print("函数 a")
def b():
    a()
    print("函数 b")
def c():
    b()
    print("函数 c")
def d():
    c()
    print("函数 d")
d()
注意体会上述代码的执行顺序. 可以通过画图的方式来理解.

 函数之间的调用关系, Python 中会使用一个特定的数据结构来表示, 称为 函数调用栈 . 每次函数调用, 都会在调用栈里新增一个元素, 称为 栈帧.

  • 可以通过 PyCharm 调试器看到函数调用栈和栈帧.
  • 在调试状态下, PyCharm 左下角一般就会显示出函数调用栈.
每个函数的局部变量 , 都包含在自己的栈帧中
def a():
    num1 = 10
    print("函数 a")
def b():
    num2 = 20
    a()
    print("函数 b")
def c():
    num3 = 30
    b()
    print("函数 c")
def d():
    num4 = 40
    c()
    print("函数 d")
d()
  • 选择不同的栈帧, 就可以看到各自栈帧中的局部变量.
  • 调用函数,则生成对应的栈帧;
  • 函数结束,则对应的栈帧消亡(里面的局部变量也就消失了)
思考 : 上述代码 , a, b, c, d 函数中的局部变量名各不相同 . 如果变量名是相同的 , 比如都是 nums  , 那么这四个函数中的 nums 是属于同一个变量 , 还是不同变量呢 ?

def a():
    nums = 10
    print("函数 a")
def b():
    nums = 20
    a()
    print("函数 b")
def c():
    nums = 30
    b()
    print("函数 c")
def d():
    nums = 40
    c()
    print("函数 d")
d()
  • 每个变量虽然同名,但其是不同变量。属于不同的函数作用域。
  • 每个变量也是保存在各自的栈帧中的(每个栈帧也是保存在内存上),变量本质就是一块内存空间。

4.函数递归

4.1 递归的概念

递归是嵌套调用 中的一种特殊情况 , 即一个函数嵌套调用自己 .
代码示例 : 递归计算 5!
#写一个函数,求n的阶乘(n是正整数)

def factor(n):
    if n == 1:
        return 1
    return n * factor(n - 1)


result = factor(5)
print(result)

上述代码中, 就属于典型的递归操作 . factor 函数内部 , 又调用了 factor 自身 .
def factor(n):
    result = 1
    for i in range(1,n+1):
        result *= i
    return result


print(factor(5))
注意 : 递归代码务必要保证
  • 存在递归结束条件. 比如 if n == 1 就是结束条件. n 1 的时候, 递归就结束了.
  • 每次递归的时候, 要保证函数的实参是逐渐逼近结束条件的.
如果上述条件不能满足 , 就会出现 " 无限递归 " . 这是一种典型的代码错误:
def factor(n):
    return n * factor(n - 1)


result = factor(5)
print(result)

  • 如前面所描述, 函数调用时会在函数调用栈中记录每一层函数调用的信息.
  • 但是函数调用栈的空间不是无限大的. 如果调用层数太多, 就会超出栈的最大范围, 导致出现问题.

4.2 递归的优点

  • 递归类似于 "数学归纳法" , 明确初始条件, 和递推公式, 就可以解决一系列的问题.
  • 递归代码往往代码量非常少.

4.3 递归的缺点

  • 递归代码往往难以理解, 很容易超出掌控范围
  • 递归代码容易出现栈溢出的情况
  • 递归代码往往可以转换成等价的循环代码. 并且通常来说循环版本的代码执行效率要略高于递归版本.
实际开发的时候 , 使用递归要慎重 !

5. 参数默认值

Python 中的函数 , 可以给形参指定默认值 .
带有默认值的参数 , 可以在调用的时候不传参 .
代码示例 : 计算两个数字的和
def add(x, y, debug=False):
    if debug:
        print(f'调试信息: x={x}, y={y}')
    return x + y
print(add(10, 20))
print(add(10, 20, True))
此处 debug=False 即为参数默认值 . 当我们不指定第三个参数的时候 , 默认 debug 的取值即为 False.

带有默认值的参数需要放到没有默认值的参数的后面
def add(x, debug=False, y):
    if debug:
        print(f'调试信息: x={x}, y={y}')
    return x + y
print(add(10, 20))

多个带有默认参数的形参,这些 都得放在后面!

6. 关键字参数

在调用函数的时候 , 需要给函数指定实参 . 一般默认情况下是按照形参的顺序 , 来依次传递实参的 .

但是我们也可以通过 关键字参数, 来调整这里的传参顺序, 显式指定当前实参传递给哪个形参.

def test(x, y):
    print(f'x = {x}')
    print(f'y = {y}')
test(x=10, y=20)
test(y=100, x=200)
形如上述 test(x=10, y=20) 这样的操作 , 即为 关键字参数 .
  1. 位置参数和关键字参数还能混着使用,只不过混着用的时候要求位置参数在前,关键字参数在后。
  2. 关键字参数,一般搭配默认参数来使用的。
  3. 一个函数,可以提供很多的参数,来实现对这个函数的内部功能做出一些调整设定。为了降低调用者的使用成本,就可以把大部分参数设定为默认值。当调用者需要调整其中的一部分参数的时候,就可以搭配关键字参数来进行操作。

7. 小结

函数是编程语言中的一个核心语法机制 . Python 中的函数和大部分编程语言中的函数功能都是基本类似的.
我们当下最关键要理解的主要就是三个点 :
  • 函数的定义
  • 函数的调用
  • 函数的参数传递
我们在后续的编程中 , 会广泛的使用到函数 . 在练习的过程中再反复加深对于函数的理解 .

猜你喜欢

转载自blog.csdn.net/m0_57859086/article/details/128666241