目录
1.函数目的
-
代码重用:当你有一个复杂的任务或一段需要重复执行的代码时,可以将其封装在一个函数中。这样,你可以在不同的地方多次调用这个函数,而不需要重复编写相同的代码。这不仅可以节省时间,还可以减少错误。
-
模块化:通过将代码组织成函数,你可以将程序划分为更小的、更易于管理的部分。每个函数都负责执行一个特定的任务,这使得代码更加清晰和易于理解。此外,模块化还可以提高代码的可测试性,因为你可以单独测试每个函数的功能。
-
提高可读性:良好的函数命名和参数选择可以使代码更具可读性。函数封装了一段复杂的逻辑,使得代码结构更清晰。通过给函数提供描述性的名称,读者可以更容易地理解函数的功能和用途。
-
可维护性:当代码发生变化或需要修改时,定义函数的代码比没有函数的代码更容易修改。如果一段逻辑被封装在一个函数中,并且该函数在其他地方没有被多次使用,那么你只需要修改这个函数,而不需要搜索整个程序来找到所有需要修改的地方。
2.函数定义
函数是指一个能够执行特定任务或计算并返回结果的代码块,这个代码块有一个明确的名称(即函数名),并且可以通过指定参数(如果有的话)来调用。使用def
关键字开始,后面跟着函数名、参数列表(括在括号中,可以为空)以及一个冒号。函数体(即函数内部的代码块)则通过缩进来定义。
函数定义的基本语法如下:
def 函数名(参数列表):
"""这里是可选的文档字符串,用于描述函数的功能和使用方式"""
# 函数体的开始
# 这里是函数的实现代码
# ...
# 函数体的结束
return 返回值 # 可选,用于返回函数执行的结果
3.函数声明
这是一个对函数名为go_home的函数的声明:
def say():
print("hello")
4.函数调用
在Python中,我们只需写出函数名(如果需要,后面跟着参数和括号),Python就会执行该函数的代码块。
def say():
print("hello")
# 调用函数
say() # hello
5.函数形参和实参
简单来说,函数的形参就是在定义函数时,写在小括号里的参数,函数的实参就是在调用函数的时候,写在小括号里的参数。
下面给出一段代码来具体说明:
def go_home(name, work):
print(f"{name},你妈妈喊你回家{work}啦")
go_home("马云", "吃饭") # 马云,你妈妈喊你回家吃饭啦
go_home("马化腾", "收衣服") # 马化腾,你妈妈喊你回家收衣服啦
这段代码中,定义函数时出现在小括号中的name和work就是形参,而调用函数时出现在小括号中的“马云”,“吃饭”,“马化腾”,“收衣服”就是实参,调用函数时就将这些实参赋予给形参,从而实现函数的调用。
6.函数返回值
如果定义函数的时候没有写return,则函数的返回值默认为None,否则返回return后的执行语句。
示例如下:
def my_fun1():
print("好好学习") # 好好学习
print(my_fun1()) # None
def my_fun2():
a = 10
b = 20
return a + b
print(my_fun2()) # 30
函数my_fun1()没有return,打印函数则返回None,而函数my_fun2()给出了return,则返回a + b的值。
8.函数的参数类型
在Python中,函数的参数类型大致分为四种:位置参数、可变元组参数、可变字典参数、关键字参数。
下面通过一段简单的代码统一解释:
def my_fun(n, *args, info="hello", work="吃", **kwargs):
print(n)
print(args, type(args))
print(info)
print(work)
print(kwargs, type(kwargs))
my_fun(2, "小王", "小张", "小李", info="hi", work="睡", place1="地板", place2="床")
上述代码的输出结果为:2;('小王', '小张', '小李') <class 'tuple'>;hi;睡;{'place1': '地板', 'place2': '床'} <class 'dict'>。
其中n为位置参数,它也称为必选参数,是函数定义中最常见的参数类型。在函数调用时,这些参数必须按照它们在函数定义中的顺序提供。
*args为可变元组参数,它使用*args
(args
可以替换为其他名称)来表示,允许函数接受任意数量的位置参数,打印的结果存放在元组中。
info和work都为可变关键字参数,关键字参数允许我们在函数调用时通过参数名来指定参数值,这样可以打破位置参数的顺序限制。
**kwargs为可变字典参数,它使用**kwargs
(kwargs
可以替换为其他名称)来表示,允许函数接受任意数量的关键字参数,打印的结果存放在字典中。
9.变量的作用域(global和nonlocal)
在Python中,函数中变量的作用域分为全局变量和局部变量。
全局变量在程序执行时创建,在程序结束时销毁,所有函数外部定义的变量都属于全局作用域,这些变量被称为全局变量。全局变量可以在程序的任意位置被访问,包括在函数内部。在函数内部,可以通过直接引用全局变量的名字来访问和修改全局变量(但在某些情况下,使用global
关键字可以明确声明你要修改的是全局变量)。
下面是代码示例:
def my_fun():
# global通过对其后的变量进行声明,声明其为全局变量
global data
print(data)
# 声明后此处的修改就是对全局变量进行修改,不声明会报错
data = 20
print(data)
my_fun()
局部变量在函数调用时创建,并在函数调用结束时销毁。在函数内部定义的变量属于局部作用域,这些变量被称为局部变量。局部变量只能在函数内部被访问,在函数外部无法直接访问或修改局部变量的值。每次函数调用时,都会创建一个新的局部作用域,因此即使在同一个函数中,每次调用也会有自己的局部变量副本。
下面是代码示例:
i = 1000
def my_fun1():
# 声明新的局部变量
i = 10
print("myfun1", i)
def my_fun2():
j = 20
# 声明非本地变量 但是也不是全局变量
nonlocal i
i = i + 1
print("myfun2", i, j)
return my_fun2
r = my_fun1() # myfun1 10
r() # myfun2 11 20
r() # myfun2 12 20
r() # myfun2 13 20
r() # myfun2 14 20
# 函数外部的全局变量 始终没有改变
print(i) # 1000
其中i = 1000是全局变量,所以从始至终没有改变;j = 20 是局部变量,只能在本函数段内使用,一旦出了当前函数,就无法再通过别的方式访问j;i = 10被nonlocal定义,声明它既不是全局变量也不是本地变量,而是一个全新的变量,故随着r()的每次执行都会加一并保存当前值。
10.递归函数
在Python中,递归函数是一种特殊的函数,它直接或间接地调用自身来完成计算。它在定义的时候和普通函数没有什么区别,但是要注意的是,使用递归函数的时候一定要有递归出口。
递归出口是递归函数停止递归的条件。这是一个或多个条件判断,当这些条件为真时,函数不再调用自身,而是返回一个值。没有递归出口,递归函数将会无限循环调用自身,导致栈溢出错误。
下面是一个计算阶乘的递归函数:
# 递归求阶乘
def get_multi(v):
if v == 1:
return 1
else:
return v * get_multi(v - 1)
在这个例子中, 函数首先检查基本情况(v == 1
),如果条件为真,它返回1(因为1的阶乘是1)。否则,它执行递归情况,调用自身但参数为v - 1
,并将结果与v相乘。这个过程会不断重复,每次递归调用都使n
减小,直到达到递归出口。
11.匿名函数
在Python中,匿名函数是通过使用内置的 lambda
关键字来创建的。lambda
表达式可以定义简单的小型匿名函数,这些函数主要用于需要一个函数对象,但又不希望用 def
语句定义一个单独函数的情况。匿名函数的格式为:lambda 形参列表: 单行表达式。它可以无形参,可以有一个形参,也可以有多个形参。
下面是代码示例:
my_fun = lambda: print("抬起头")
my_fun() # 抬起头
# 可以有一个形参
my_fun = lambda msg: print(msg)
my_fun("下课啦") # 下课啦
# 可以有多个形参
my_fun = lambda name, msg: print(f"{name}, {msg}")
my_fun("小明", "放学啦") # 小明, 放学啦
若其中的单行表达式为逻辑表达式,默认有返回值。
下面是代码示例:
my_fun = lambda x, y: x + y
print(my_fun(10, 20)) # 30
my_fun = lambda a, b: a if a > b else b
print(my_fun(100, 200)) # 200