第九章 函数

预习

课程安排

  • 函数

课堂笔记

  • 1.函数简介
  • 2.函数的参数
  • 3.不定长参数
  • 4.参数的解包
  • 5.函数的返回值
  • 6.文档字符串
  • 7.函数的作用域
  • 8.命名空间
  • 9.递归函数
  • 10.高阶函数
  • 11.闭包
  • 12.装饰器的引入
  • 13.装饰器的使用

上课

1.函数简介

  • 函数也是一个对象
  • 函数用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次调用

语法:
def 函数名([形参1,形参2,形参3......]):
代码块

注意:函数名必须符合标识符的规范(可以包含字母、数字、下划线但是不能以数字开头)

  • 函数中保存的代码不会立即执行,必须调用之后才能执行。
  • print是函数对象 print()是调用函数

2.函数的参数

在定义函数的时候可以在函数后面定义数量不等的参数,相当于形参,多个形参用逗号隔开。

2.1 形参和实参

  • 形参(形式参数) 定义形参就相当于在函数内部声明了变量,但是并不是赋值
  • 实参(实际参数)指定了形参,那么在调用函数时必须传递实参,实参将会赋值给对应的形参,简单来说有几个形参就要有几个实参
  • 实参可以是任意类型的对象

2.2 函数的传递方式

  • 定义形参时,用户可以指定默认值。如果用户传递了参数值,默认值不生效,如果用户没有传递参数,默认值生效
  • 位置参数:就是将对应位置的实参赋值给对应位置的形参
  • 关键字参数:关键字参数可以不按照形参定义的顺序传参,而根据参数名传参
  • 混合使用位置参数和关键字参数的时候,需要将位置参数写在关键字参数的前面

3.不定长参数

  • 定义函数时,可以在形参前面加一个*,这样这个形参可以获取到所有的实参,它会将所有的实参保存到一个元组中
  • **的形参可以接收其他的关键字参数 它会将这些参数统一保存到字典当中
def fn3(**a):
    print('a =', a)
fn3(b=2,d=1,c=3)
>>> a = {'b': 2, 'd': 1, 'c': 3}

4.参数的解包

  • 传递实参时,也可以在字典前添加*号,这样它会自动将字典中的元素依次作为参数传递
  • 要求字典中元素的个数必须与形参的个数一致

5.函数的返回值

  • 返回值就是函数执行以后返回的结果
  • 通过return来指定函数的返回值
  • return后面可以跟任意对象,甚至是一个函数
  • 如果仅仅写一个return,或者不写return,则相当于return None
  • 在函数中 return后面的代码都不会执行,return一旦执行函数自动结束

6.文档字符串

  • help()是Python中的内置函数,通过help()函数可以查询Python中函数的用法
  • 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是对函数的说明
  • 通过help()函数来查询函数的用法,显示文档字符串的内容
help(print)

def fn(a:bool,b:int,c:str)->int:
    '''
    这个函数式一个文档字符串的实例
    参数
        a:作用 类型 默认值......
        b:作用 类型 默认值......
        c:作用 类型 默认值......
    '''
    return 100
help(fn)

7.函数的作用域

  • 作用域(scope)
  • 作用域指的是变量生效的区域
  • 在Python中一共有两种作用域
    • 全局作用域
    • 全局作用域在程序执行时创建,在程序执行结束时销毁
    • 所有函数以外的区域都是全局作用域
    • 在全局作用域中定义的变量,都是全局变量,全局变量可以在程序的任意位置访问
    • 函数作用域
    • 函数作用域在函数调用时创建,在调用结束时销毁
    • 函数每调用一次就会产生一个新的函数作用域
    • 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问

如果希望在函数内部修改全局变量,则使用global关键字来声明
在函数内部使用全局变量,此时修改a时,就是在修改全局变量

8.命名空间

  • 命名空间实际上就是一个字典,是一个专门用来存储变量的字典
  • locals()用来获取当前作用域的命名空间
  • 如果在全局作用域中调用locals(),则会获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间
  • 返回值是一个字典

9.递归函数

  • 递归是解决问题的一种方式,它的整体思想是将一个大问题分解为一个个的小问题,直到问题无法分解为止,再去解决问题
  • 递归式函数有2个条件:
    • 1.基线条件:问题可以被分解为最小问题,当满足基线条件时,递归就不执行了
    • 2.递归条件:可以将问题继续分解的条件

9.1 任意数任意幂练习

def fn(n,i):
# 参数 n 要做i次幂运算
# 1. 基线条件
    if i == 1:
        return n
# 2. 递归条件
    return n * fn(n,i-1)

9.2 回文练习

def fn2(s):
# 参数s就是要检查的字符串
# 1.基线条件
# 字符串的长度小于2 则字符串一定是个回文
    if len(s)<2:
        return True
# 第一个字符和最后一个字符不相同,则一定不是回文字符串
    elif s[0] != s[-1]:
        return False
# 2.递归条件
    return s[0] == s[-1] and fn2(s[1:-1])

10.高阶函数

概念:

  • 接收一个或多个函数作为参数
  • 将函数作为返回值返回
  • 当我们使用一个函数作为参数,实际上是将指定的代码传递进了目标函数。
lst = [1,2,3,4,5,6,7,8,9,10]

# 定义一个函数 用来加测一个偶数
def fn2(i):
    if i % 2 == 0:
        return True


# 定义一个函数 用来检测是否大于5
def fn3(i):
    if i > 5:
        return True
    return False

# 定义一个函数 用来检测是否是3的倍数
def fn4(i):

    if i % 3 == 0:
        return True
    return False


def fn(func,lst):
    # 参数lst 要进行筛选列表
    # 创建一个新的列表
    new_lst = []
    for n in lst:
        # 判断n的奇偶
        if func(n):
            new_lst.append(n)
    return new_lst
  • 匿名函数: filter(参数1,参数2)
    • 可以从序列中过滤出符合条件的元素,保存到一个新的序列中
    • 参数1:函数 根据该函数来过滤序列
    • 参数2: 需要过滤的序列
    • 返回值:过滤后的新序列

11.闭包

  • 将函数作为返回值也是高阶函数我们也称为闭包
  • 闭包的好处
    • 通过闭包可以创建一些只有当前函数能访问的变量
    • 可以将一些私有数据藏到闭包中
  • 形成闭包的条件
    • 函数嵌套
    • 将内部函数作为返回值返回
    • 内部函数必须要使用到外部函数的变量
  • 闭包必要性的举例:
  • 目的:保证nums的数据安全
def make_average():
    nums = []
    # 定义一个函数 计算平均值   
    def average(n):
        # 将n添加到列表当中
        nums.append(n)
        # 求平均值
        return sum(nums)/len(nums)
    return average
--------------------------------------------------------------------------------
调用:
a = make_average()
print(a(10))
print(a(2,3,4,5,6,7,8,9,22,56))

12.装饰器的引入

  • 我们可以直接通过修改函数中的代码来完成需求,但是会产生以下一些问题
    • 如果修改的函数多,修改起来会比较麻烦
    • 不方便后期的维护
    • 这样做会违反开闭原则(ocp)
      • 程序设计要求:开放对程序的扩展,关闭对程序的修改

13.装饰器的使用

  • 通过装饰器,可以在不修改原来函数的情况下来对函数扩展
  • 在开发中,我们都是通过装饰器来扩展函数的功能的
def start_end(old):
    # 用来对其他的函数进行扩展 扩展函数执行的时候 打印 开始执行 执行后打印执行结束
    # 参数 old 要扩展的函数对象
    # 创建一个函数
    def new_function(*args,**kwargs):
        print('开始执行')
        # 要调用被扩展的函数
        result = old(*args,**kwargs)
        print('执行结束')
        return result
    # 返回新函数
    return new_function
  • 也可以使用@扩展函数来代替
@start_end
def speak():

    print('大家加油')

speak()

作业

  • 汉诺塔游戏,现在有ABC三根柱子。
    要求:将A柱所有的圆盘放到C柱。在移动过程中可以借助B柱。并且规定大圆盘不能放小圆盘上⾯,每次只能移动一个盘子。
    用递归的方式来解决汉诺塔问题。


  • 把函数这一章总体的复习一遍。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。