(P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

时间:2021-09-03 01:25:26


文章目录

  • 1.形参和实参
  • 2.关键字参数
  • 3.默认参数
  • 4.收集参数(可变参数)
  • 5.函数与过程
  • 6.局部变量与全局变量
  • 7.函数嵌套和闭包
  • 8.lambda表达式
  • 9.递归

1.形参和实参

  • 函数文档:对参数和返回值有介绍
    '函数定义过程中的name是叫形参’是函数文档,其功能与下面额注释是一样的
>>> def MyFirstFunction(name):
  '函数定义过程中的name是叫形参'
  #因为Ta只是一个形式,表示占据一个参数位置
  print('传递进来的' + name + '叫做实参,因为Ta是具体的参数值!')
>>> MyFirstFunction('小甲鱼')
  • 函数文档的使用方法

    类似的可以查看print函数的函数文档

2.关键字参数

  • 关键字参数,用在调用函数的实参的位置,其目的就是给形参下一个定义,这样的话,python会按照关键字去索引,而不是用顺序去索引

3.默认参数

  • 默认参数(即形参中给定默认值,则在未给实参时会以默认值输出)

4.收集参数(可变参数)

  • print本身就使用了可变参数,print(xxx,xxx,xxx),用逗号隔开,会将其打包成元组,放到*objects中去
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • 测试1
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • 测试2,若收集参数后面还有自己其他的定制的参数,那么在调用函数的时候就应该使用关键字参数来定制,否则python会将所有实参作为收集参数的范畴了
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • 测试3:函数中有可变参数,但是后面还有其他参数,建议将其他参数设置为默认参数
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

5.函数与过程

  • 过程procedure是简单,特殊且没有返回值的
  • 函数是有返回值的
    python的所有函数都有返回值:如果有返回值,函数则返回对应值;如果没有,则返回None
  • python返回单个值,可以是一个int类型
    python返回多个值,既可以用list,也可以用tuple,默认是tuple元组
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

6.局部变量与全局变量

  • 局部变量:在局部生效如在函数中定义的变量
  • 全局变量:作用于整个模块。函数内若试图修改全局变量,Python会新建一个同名局部变量用于存储修改值,原全局变量的值不变。不要在函数内部去修改全局变量。

7.函数嵌套和闭包

  • 函数中使用global
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • 嵌套函数(内部函数)
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • 闭包closure,函数式编程lsp
    若在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被仍为是闭包。
    return FunY直接返回函数对象
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • x=5对于Fun2()来讲是非全局变量的局部变量,在Fun2()中试图对x修改,则外部的x则会被屏蔽起来,对于Fun2()来说x是局部变量,根本就没有定义,具体看报错
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • 由于列表不存放在栈里面,所以可以做如下的修改:
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • 使用nonlocal,声明x不是局部变量,也可以
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

8.lambda表达式

  • lambda表达式用法。lambda表达式是匿名函数,没有名字def
lambda x : 2 * x +1
x是参数,2* x +1是表达式
返回值是函数对象
  • 测试:
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • lambda表达式的作用
    1)Python写一些执行脚本时,使用lambda就可以省下定义函数的过程,比如说我们只是需要写一个简单的脚本来管理服务器时间,我们就不需要专门定义一个函数然后再写调用,使用lambda就可以使得代码更加精简。
    2)对于一些比较抽象并且整个程序执行下来只需要调用一两次的函数,有时候我们个函数起个名字也是比较头疼的问题,使用lambda就不需要考虑命名问题。
    3)简化代码的可读性,由于普通的函数阅读经常要跳到开头def定义部分,使用lambda函数可以省去这样的步骤。
  • 两个重要的BIF
    1)过滤器filter(function or None,iterable):两个参数为函数和可迭代的序列,函数定义了过滤的规则,默认过滤出真的部分。
    2)map(function or None,iterable):同filter()的两个参数相同,这个内置函数的作用是:将序列的每一个元素作为函数的参数进行运算加工,直到可迭代序列的每个元素都加工完毕,返回所有加工后的元素构成的新序列。
    从help文档中可以看到filter需要接收2个参数
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • 测试:
    使用None,将非True的内容过滤掉
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • 使用函数
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归


  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

9.递归

  • 设置递归深度
sys.setrecursionlimit(1000000)

100层是py3的保护,1000是py2的保护
  • 递归必须满足哪两个基本条件
    (1)函数调用自己;
    (2)函数设置了正确的返回值。
  • eg:•写一个求阶乘的函数
    正整数阶乘指从1乘以2乘以3乘以4一直乘到所要求的数。
    例如所给的数是5,则阶乘式是1×2×3×4×5,得到的积是120,所以120就是4的阶乘。
    假设我们n的值传入是5,那么:
非递归方式
def factorial(n):
    result = n
    for i in range(1, n):
        result *= i

    return result

number = int(input('请输入一个正整数:'))
result = factorial(number)
print("%d 的阶乘是:%d"  % (number, result))#格式化为整数类型

递归方式:
def factorial(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n-1)

number = int(input('请输入一个正整数:'))
result = factorial(number)
print("%d 的阶乘是:%d" % (number, result))
  • 测试:
  • 斐波那契数列的迭代实现
    坑爹的兔子:我们都知道兔子繁殖能力是惊人的,如下图:

    我们可以用数学函数来定义:

    求:们需要求出经历了20个月后,总共有多少对小兔崽子?(迭代 vs 递归)
迭代:
def fab(n):
    n1 = 1
    n2 = 1
    n3 = 1

    if n < 1:
        print('输入有误!')
        return -1

    while (n-2) > 0:
        n3 = n2 + n1
        n1 = n2
        n2 = n3
        n -= 1
    
    return n3

result = fab(20)
if result != -1:
    print('总共有%d对小兔崽子诞生!' % result)


递归:
def fab(n):
    if n < 1:
        print('输入有误!')
        return -1

    if n == 1 or n == 2:
        return 1
    else:
        return fab(n-1) + fab(n-2)

result = fab(35)
if result != -1:
    print('总共有%d对小兔崽子诞生!' % result)
  • 测试:
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归


  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • 汉诺塔
    n代表要移动的盘子数量,x,y,z代表三个针
  • (P17-P24)函数:形参和实参 ,关键字参数 ,默认参数,收集参数(可变参数),函数与过程,局部变量与全局变量,函数嵌套和闭包,lambda表达式,递归

  • •对于游戏的玩法,我们可以简单分解为三个步骤
    –将前63个盘子从X移动到Y上。
    –将最底下的第64个盘子从X移动到Z上。
    –将Y上的63个盘子移动到Z上。
    •问题一:将X上的63个盘子借助Z移到Y上;
    •问题二:将Y上的63个盘子借助X移到Z上。
  • eg:
def hanoi(n, x, y, z):
    if n == 1:
        print(x, ' --> ', z)
    else:
        hanoi(n-1, x, z, y) # 将前n-1个盘子从x移动到y上
        print(x, ' --> ', z) # 将最底下的最后一个盘子从x移动到z上
        hanoi(n-1, y, x, z) # 将y上的n-1个盘子移动到z上

n = int(input('请输入汉诺塔的层数:'))
hanoi(n, 'X', 'Y', 'Z')