前言
何为函数?
Python中有许多内置函数,也可以看做是方法。为了减少代码的重复编写及代码的复用,可用将重复的代码封装成一个方法,在使用时拿出来调用。
1.定义函数
Python规定了函数的格式,如:def function_name(参数):
#这是函数体
#返回值可以有,也可以没有,不写则默认返回值是None
return result
def是函数的开始;function_name是函数名称,名称要能够使他人看出该函数是干什么的;()圆括号里是参数,可以没有参数,写入参数时是不限输入量的,但是定义函数时圆括号必须有;“:”冒号必须有,不能省略,少了会报错;下方缩进的函数体是函数功能实现的具体语句;return返回值,可以有,也可以没有,不写则默认返回值是None,根据具体的函数功能灵活设置返回值。
定义好函数,函数调用可以将函数执行,函数调用格式:函数名()。如:function_name()
def water():
print("该喝水了")
print("*****")
water()
water()
water()
1.函数的形参与实参
形参:形式参数,没有固定值,调用函数时将实参赋予形参,出现在函数声明中的圆括号中。
实参:实际参数,出现在函数的调用的圆括号中。
形参与实参的使用可以使函数的功能更加强大。
def study(name, num):
for i in range(num):
print(f"{name}该去学习了")
# 函数调用写入实参
study("胡斐", 5)
print("-------------")
study("李飞", 6)
执行结果:
2.函数的返回值
函数的返回值可以看成是函数的运算结果,默认返回None,即没有返回值。
也可以通过rerturn将函数运算结果返回,return后续代码不会执行,即return可以直接将函数终止,这一点和break的功能类似。
def count(first, second):
total = (first ** second) - first
return total
r = count(5, 6)
print(r, "函数返回计算结果")
并且,Python中函数的return可以有多个返回值,最终多个返回值会放入一个元组。
3.变量的作用域
函数变量分为全局变量和局部变量。
局部变量;定义在函数内部的变量称为局部变量,这些变量的作用范围限定在函数内部,在函数执行完毕后就会被销毁。
全局变量:在函数外部定义的变量是全局变量,它们可以在整个程序中访问,包括函数内部。
使用规则:不能在函数外部使用函数内部定义的局部变量。且在for循环内部定义的局部变量,不推荐在循环外部使用。
函数内部修改全局变量方法:在函数内部想要修改全局变量,需要使用global关键字,声明以后后续的变量都是函数外部的变量,否则将会创建一个新的局部变量而不是修改全局变量的值。
# 函数变量分为全局变量和局部变量
# s = 10 是全局变量
# s = 10
#
#
# def f(m, n):
# # 函数内部的s是局部变量
# # 此时的s与全局变量s不是一个数值,函数内部的是一个新的不同于全局变量的变量
# s = m + n
# # 全局变量s可以放在函数内获取,但是不能修改
# # 如果想要在函数内部修改全局变量s,就要使用关键字global s
# # 声明现在使用的是全局变量s
# return s
# print(f(2, 4))
# 此时打印出的结果是10,是全局变量s的值
# 为什么不是函数内部s的值,是因为在函数执行完成后,s就会消失
# print(s)
4.函数参数类型
Python函数参数类型包括:位置参数、默认参数、关键字参数、可变元组参数、可变字典参数。
位置参数:是最常见的参数类型。参数的顺序决定了传递的值与函数参数的对应关系。
# 位置参数----按照位置将实参分别赋予形参
def f(m, n):
# 按照位置,将函数调用中的2赋给m,3赋给n
print(m, n)
f(2, 3)
默认参数:在函数定义时给参数指定默认值,调用函数时如果没有提供对应参数的值,则使用默认值。
# 默认参数----形参有默认值,在调用时可以不传入实参
# 如果调用时传入实参,那么其值就是对应传入的实参值
# 形参没有默认值,则必须传入实参
def f(m, n, a=3, b=1):
"""
默认参数
:param m: 形参
:param n: 形参
:param a: 形参,有默认值3,调用时可以不传入实参
:param b: 形参,有默认值1,调用时可以不传入实参
:return: None
"""
print(m, n, a, b)
f(2, 3)
关键字参数:在函数调用时指定将实参赋予某个形参,没有默认值的形参必须赋值。
# 关键字参数----在调用时可以指定关键字传入参数
def f(m, n, a=3, b=1):
print(m, n, a, b)
# 传入实参时,没有默认值的参数必须传入实参,有默认值的参数可以不传参
# 调用函数时,跳过形参a,直接指定了关键字形参b的实参是10,而a没有赋值就为默认值
f(2, 3, b=10)
可变元组参数:可以接受任意个数的参数,*args可以接受多个参数,*args接受的多个参数都放在一个元组中。
# 可变元组参数--可以接受任意个数的参数
# *args可以接受多个参数
# *args接受的多个参数都放在一个元组中
def f(m, *args, n=20):
print(m, n, args, type(args))
f(10, 50, 49, 20, n=15)
# 10 15 (50, 49, 20) <class 'tuple'>
可变字典参数:**kwargs接受其他参数,关键字不能是真实形参,即不能是函数定义是括号中的形参,可以使用其他任意的关键字来设定值,这些值会放在字典中。
# **kwargs接受其他参数
# 位置参数传完,才会传可变参数
def f(m, *args, n=20, **kwargs):
print(m, n, args, kwargs)
f(10, 50, 49, 20, n=15, c=5, d=8)
# 结果:10 15 (50, 49, 20) {'c': 5, 'd': 8}
5.匿名函数----拉姆达lambda
在 Python 中,匿名函数通常使用lambda关键字来创建。匿名函数是一种小型、一次性使用的函数,它可以接受任意数量的参数,但只能包含一个表达式。
格式:lambda 形参列表: 函数体
创建lambda函数简单例子:
f1 = lambda x: x ** 2
print(f1(5))
f2 = lambda x, y: x + y - 7
print(f2(10, 20))
匿名函数通常用于一些简单的操作,例如在排序或过滤列表时传递给高阶函数。
普通的创建函数进行排序
l0 = [
{"name": "胡天", "age": 15, "score": 90},
{"name": "孔毅", "age": 30, "score": 98},
{"name": "李飞", "age": 19, "score": 100},
]
def f(e):
"""
定义一个函数,获取到列表中的age键的值
调用函数时将返回值作为排序的标准
:param e: 形参
:return: 获取的是列表元素字典中age键对应的值
"""
return e["age"]
l0.sort(key=f)
print(l0)
使用lambda函数:
l0 = [
{"name": "胡天", "age": 15, "score": 90},
{"name": "孔毅", "age": 30, "score": 98},
{"name": "李飞", "age": 19, "score": 100},
]
# 使用拉姆达函数,没有函数名,直接写出最简洁的函数,将函数赋给key,直接以此作为排序标准
# 此时的代码比较简单没有函数名,而普通创建函数方法比较麻烦
l0.sort(key=lambda e: e["score"])
print(l0)
# 结果
# [{'name': '胡天', 'age': 15, 'score': 90}, {'name': '孔毅', 'age': 30, 'score': 98}, {'name': '李飞', 'age': 19, 'score': 100}]
6.递归函数
递归是一种函数调用自身的编程技巧。在 Python 中,可以使用递归来解决一些问题,但需要注意处理递归的终止条件,要设置递归出口,以防止无限循环。
递归经典案例:
# 递归求阶乘
def f(n):
# 出口
if n == 1:
return 1
else:
return n * f(n-1)
print(f(5))
7.函数使用案例:判断质数
# 封装判断质数方法
def is_prime(n):
for i in range(2, n):
if n % i == 0:
return False
else:
return True
s = is_prime(20)
print(s)
# 封装判断质数对的方法
def get_prime_pairs(start, stop, step):
for i in range(start, stop - 1 - step):
if is_prime(i) and is_prime(i + step):
print((i, i + 6))
get_prime_pairs(2, 980, 6)
小结
函数是Python中比较难的一个知识点,自己封装函数时要注意形参与实参的对应关系。
递归函数比较难以理解,首先递归在每一个系统里都有深度限制,且递归的效率可能不如迭代,而且存在堆栈溢出的风险。在使用递归时,确保问题的规模能够收敛到基本情况,并考虑使用迭代或其他更高效的方法。所以递归函数能不使用就不使用。