第五章 函数

5.1 函数的介绍与好处

5.1.1 基本介绍

(1)为完成某一功能的程序指令(语句)的集合,称为函数;

(2)在Python中,函数分为系统函数、自定义函数。

系统函数包括内置函数和模块提供的函数(由Python提供)。

内置函数:内置函数 — Python 3.13.5 文档

模块提供的函数:math --- 数学函数 — Python 3.13.5 文档

自定义函数:定义函数使用关键字def,后跟函数名与括号内的形参列表。函数语句从下一行开始,并且必须缩进。(程序员根据业务需要开发的)

5.1.2 函数的好处

(1)提高代码的复用性;

(2)可以将实现的细节封装起来,然后供其他用户来调用即可。

5.2 函数的定义

(1)函数代码块以def关键字开头,后接函数标识符名称和圆括号();

(2)函数内容以冒号:起始,并且缩进;

(3)函数参数(a,b),可以有多个,也可以没有,即直接是(),(a,b)也称为形参列表;

(4)函数可以有返回值,也可以没有,如果没有return相当于返回None。

5.3 函数的调用

(1)函数定义好了,并不会自动执行,需要程序员调用,才会执行;

(2)调用方式:函数名(实参列表),比如max(10,20)。

5.4 函数的调用机制

5.4.1 通俗理解

5.4.2 函数的调用过程(重要)

以get_sum为例分析:

def cal04():
    # 接受用户的输入
    n1 = int(input("请输入一个数:"))
    n2 = int(input("请输入一个数:"))
    oper = input("请输入运算符 + - * /:")
    # 统计结果
    res = 0.0
    # 多分支的判断
    if oper == "+":
        res = n1 + n2
    elif oper == "-":
        res = n1 - n2
    elif oper == "*":
        res = n1 * n2
    elif oper == "/":
        res = n1 / n2
    else:
        print("输入的运算符不对。")
    print(n1, oper, n2, "=", res)
# 使用cal04()
cal04()

5.5 return语句

(1)基本语法:

def 函数名(参数列表):
    语句...
    return 返回值

(2)说明:如果没有return语句,默认返回None,None是内置常量,通常用来代表空值的对象。(内置常量 — Python 3.13.5 文档

5.6 函数注意事项和使用细节

(1)函数的参数列表可以是多个,也可以没有;

(2)函数的命名遵循标识符命名规则和规范;

def 2f():
    print("2f")
def a-b():
    print("a-b")

(3)函数中的变量是局部的,函数外不生效;

def hi():
    n = 10
    print("n = ", n)
hi()

(4)如果同一个文件,出现两个函数名相同的的函数,则以就近原则进行调用;

def cry(n):
    print("cry()..hi...", n)
def cry():
    print("cry()..ok...")
cry()

(5)调用函数时,根据函数定义的参数位置来传递参数,这种传参方式就是位置参数,传递的实参和定义的形参顺序个数必须一致,同时定义的形参,不用指定数据类型,会根据传入的实参决定;

def car_info(name, price, color):
    print(f"name->{name}  price->{price}  color->{color}")
# 传递的实参和定义的形参顺序和个数必须一致,否则报TypeError报错
car_info("宝马", 500000, "红色",11)

(6)函数可以有多个返回值;

# 比如函数接受两个数,返回这两个数的和、差
def f2(n1, n2):
    return n1 + n2, n1 - n2
r1, r2 = f2(10, 20)
print(f"r1->{r1}  r2->{r2}")

(7)函数支持关键字参数,即函数调用时,可以通过“形参名=实参值”形式传递参数,这样可以不受参数传递顺序的限制;

def book_info(name, price, author, amount):
    print(f"name->{name}  price->{price}  author->{author}  amount->{amount}")
# 通常调用方式,一一对应
book_info("红楼梦", 60, "曹雪芹", 30000)
book_info("红楼梦", 60, 30000, "曹雪芹")
# 关键字参数
print("--------关键字参数---------")
book_info(name="红楼梦", price=60, author="曹雪芹", amount=30000)
book_info("红楼梦",60,amount=30000,author="曹雪芹")

(8)函数支持默认参数/缺省参数;

定义函数时, 可以给参数提供默认值, 调用函数时, 指定了实参, 则以指定为准, 没有指定, 则以默认值为准)

def book_info2(name='<<thinking in python>>', price=66.8, author='龟叔', amount=1000):
    print(f"name->{name} price->{price} author->{author} amount->{amount}")
book_info2()
book_info2('<<study python>')

默认参数,需要放在参数列表后

def book_info3(name, price, author='龟叔', amount=1000):
    print(f"name->{name} price->{price} author->{author} amount->{amount}")
# 调用测试
book_info3("<<python 揭秘>>", 999)
# 错误的写法
# def book_info4(author='龟叔', amount=1000, name, price):
#     print(f"name->{name} price->{price} author->{author} amount->{amount}")

(9)函数支持可变参数/不定长参数;

应用场景:当调用函数时,不确定传入多少个实参的情况

传入的多个实参,会被组成一个元组(tuple),元组可以储存多个数据项。

def sum(*args):
    # 输出了args的数据和类型 (1, 2)
    print(f"args->{args} 类型是->{type(args)}")
    total = 0
    # 对args进行遍历, 即对元组tuple遍历
    for ele in args:
        total += ele
    return total
# 调用测试
result = sum(1, 2)
print(f"result->{result}")

result = sum(1, 2, 3, -10)
print(f"result->{result}")

result = sum()
print(f"result->{result}")

(10)函数的可变参数/不定长参数,还支持多个关键字参数,也就是多个“形参名=实参值”;

应用场景:当调用函数时,不确定传入多少个关键字参数的情况name="xx",price=90

传入的多个关键字参数,会组成一个字典(dict),字典可以储存多个键=值的数据项。

def person_info(**args):
    # 输出args的数据 {'name': 'hsp', 'age': 18, 'email': 'hsp@qq.com'}和 类型
    print(f"args->{args} 类型->{type(args)}")
    # 遍历args, 是一个字典, 下面的arg_name就是取出各个参数名,
    # args[arg_name]就是取出参数值
    for arg_name in args:
        print(f"参数名->{arg_name} 参数值->{args[arg_name]}")
# 测试
person_info(name="hsp", age=18, email="hsp@qq.com")
person_info(name="hsp", age=18, email="hsp@qq.com", sex="男", address="北京")
person_info()

(11)Python调用另一个.py文件中的函数。

# 定义函数add
def add(x, y):
    print("x + y =", x + y)
# 在f2.py使用f1.py的函数
# 导入f1.py(模块),就可以使用了
import f1
f1.add(10, 30)
f1.add(10, 40)
f1.add(10, 50)

5.7 函数的传参机制

5.7.1 字符串和数值类型传参机制

"""
    字符串和数值类型传参机制
"""
# 定义函数f1
def f1(a):
    print(f"f1()a的值为:{a},地址是:{id(a)}")
    a += 1
    print(f"f1()a的值为:{a},地址是:{id(a)}")
# 定义变量a = 10
a = 10
print(f"调用f1()前,a的值为:{a},地址是:{id(a)}")
# 调用f1(a)
f1(a)
print(f"调用f1()后,a的值为:{a},地址是:{id(a)}")
# 定义函数f2
def f2(name):
    print(f"f2()name的值为:{name},地址是:{id(name)}")
    name += "hi"
    print(f"f2()name的值为:{name},地址是:{id(name)}")
# 输出一个分隔符,方便观察
print("-------------------")
name = "duye"
print(f"调用f2()前,name的值为:{name},地址是:{id(name)}")
f2(name)
print(f"调用f2()后,name的值为:{name},地址是:{id(name)}")

字符串和数值类型是不可变数据类型,当对应的变量的值发生了变化时,它对用的内存地址会发生改变。

5.7.2 list、tuple、set和dict传参机制

5.8 函数的递归调用

5.8.1 基本介绍

简单来说:递归就是函数自己调用自己,每次调用时传入不同的值;递归有助于编程者解决复杂问题,同时可以让代码变得简洁。

5.8.2 递归能解决什么问题

(1)各种数学问题:8皇后问题、汉诺塔、阶乘问题、迷宫问题等等;

(2)各种算法中也会使用到递归,比如快排、归并排序、二分查找、分治算法等;

(3)将用栈解决的问题->递归代码比较简洁。

5.8.3 递归举例

(1)打印问题

def test(n):
    if n > 2:
        test(n - 1)
    print("n = ",n)
# 调用test(4)
test(4)

(2)阶乘问题

def factorial(n):
    if n == 1:
        return 1
    else:
        return factorial(n - 1) * n
# 执行
print(factorial(4))

5.8.4 递归重要规则

(1)执行一个函数时,就创建一个新的空间(栈空间);

(2)函数的变量是独立的,比如n变量;

(3)递归必须向退出递归的条件逼近,否则就是无限递归,就会出现RecursionError:maximum recursion depth exceeded

(4)当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁。

5.8.5 递归调用应用实例——汉诺塔

def hanoi_tower(num, a, b, c):
    """
    输出指定num个盘子移动的顺序
    :param num: 指定盘子数
    :param a: 表示A柱子
    :param b: 表示B柱子
    :param c: 表示C柱子
    :return:
    """
    # 如果只有一个盘子
    if num == 1:
        print("第一个盘子从:", a, "->", c)
    else:
        # 有多个盘, 我们认为只有两个, 上面所有的盘和最下面的盘
        # 移动上面所有的盘到B柱子,这个过程会借助到C柱子
        hanoi_tower(num - 1, a, c, b)
        # 移动最下面的盘
        print(f"第{num}个盘从: {a} -> {c}")
        # 把上面所有的盘从B柱子移动到C柱子,这个过程会使用到A柱子
        hanoi_tower(num - 1, b, a, c)

# 测试一把
hanoi_tower(3, "A", "B", "C")

5.9 函数作为参数传递

(1)函数作为参数传递,传递的不是数据,而是业务处理逻辑;

(2)一个函数,可以接收多个函数作为参数传入。

5.10 lambda匿名函数

5.10.1 基本介绍

如果我们有这样一个需求,需要将函数作为参数进行传递,但是这个函数只使用一次,这时,我们可以考虑使用lambda匿名函数。

函数的定义:

def关键字,可以定义带有名称的函数,可以重复使用;

lambda关键字,可以定义匿名函数(无名称),匿名函数只能使用一次;

匿名函数用于临时创建一个函数,只使用一次的场景。

5.10.2 匿名函数基本语法

lambda形参列表:函数体(一行代码);

lambda关键字,表示定义匿名函数;

形参列表:比如num1,num2表示接收两个参数。

5.11 全局变量和局部变量

5.11.1 基本介绍和使用

(1)全局变量:在整个程序范围内都可以访问,定义在函数外,拥有全局作用域的变量;

(2)局部变量:只能在其被声明的函数范围内访问,定义在函数内部,拥有局部作用域的变量。

5.11.2 注意事项和细节

(1)未在函数内部重新定义n1,那么默认使用全局变量n1;

(2)在函数内部重新定义了n1,那么根据就近原则,使用的就是函数内部重新定义的n1;

(3)在函数内部使用global关键字,可以标明指定使用全局变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值