六、Python —— 函数
文章目录
- 一、函数基础
- 1.1、编写函数
- 1.2、调用函数
- 1.3、形参和实参
- 1.3.1、形参的初始化方式
- 1.3.2、带默认值的形参
- 1.4、变量的作用域
- 1.5、嵌套定义函数
- 1.6、pass 语句
- 二、参数传递
- 2.1、值传递
- 2.2、引用传递
- 三、return 语句
- 四、lambda 表达式
- 五、函数递归
一、函数基础
Python 中一个典型的函数定义包括以下部分:
- 关键字 def
- 函数名称
- 由 0 个或多个形参组成的列表
- 函数体
1.1、编写函数
一个求阶的函数:
def fact(n):
res = 1
for i in range(1, n + 1):
res *= i
return res
1.2、调用函数
函数的调用完成两项工作:
- 用实参初始化函数对应的形参
- 将控制权转移给被调用的函数
print("我们要计算5的阶乘,答案是:")
print(fact(5)) # 输出 120
print("计算结束啦!")
1.3、形参和实参
实参 指调用函数时传入的变量或常量,形参 指定义函数时参数列表里的变量,形参列表可以为空。
1.3.1、形参的初始化方式
调用函数时会 用实参去初始化形参,初始化的 顺序 有两种:
- 第一种是 用位置实参 来初始化形参。顾名思义,实参会按位置关系来初始化形参,第一个实参初始化第一个形参,第二个实参初始化第二个形参,依此类推。形参和实参的个数必须匹配。例如:
def f(a, b, c, d):
print("a =", a, end=", ")
print("b =", b, end=", ")
print("c =", c, end=", ")
print("d =", d)
f(1, True, "Python", 4.2) # 输出 a = 1, b = True, c = Python, d = 4.2
f(1, True, "Python", 4.2, 3) # 会报错,因为实参个数多于形参
f(1, True, "Python") # 会报错,因为实参个数少于形参
- 第二种是 用关键字实参 来初始化形参。此时实参不再按位置关系来初始化形参,而是按变量名初始化。例如:
def f(a, b, c, d):
print("a =", a, end=", ")
print("b =", b, end=", ")
print("c =", c, end=", ")
print("d =", d)
f(b=1, c=True, a="Python", d=4.2) # 输出 a = Python, b = 1, c = True, d = 4.2
- 两种方式也可以 混合使用,但是 位置实参一定要放到关键字实参 之前。也就是说,位置实参只能初始化前若干个实参。例如:
def f(a, b, c, d):
print("a =", a, end=", ")
print("b =", b, end=", ")
print("c =", c, end=", ")
print("d =", d)
f(1, 2, d="Python", c=4.2) # 输出 a = 1, b = 2, c = 4.2, d = Python
f(1, b=3, "Python", d=4.2) # 会报错,因为位置实参位于关键字实参后面了。
1.3.2、带默认值的形参
形参也可以 设置默认值,但所有带默认值的形参必须是 最后几个。当某些形参没有被初始化时,这些形参会使用默认值。例如:
def f(a, b, c=3, d="Python"):
print("a =", a, end=", ")
print("b =", b, end=", ")
print("c =", c, end=", ")
print("d =", d)
f(1, 2) # c和d没有被初始化,采用默认值。输出 a = 1, b = 2, c = 3, d = Python
f(1, b=2, d="AcWing") # c没有被初始化,采用默认值。输出 a = 1, b = 2, c = 3, d = AcWing
可以看到,位置实参和关键字实参中间是可以省略实参的,这种情况就取默认值
1.4、变量的作用域
函数内 定义的变量为 局部变量,只能在函数内部使用。
当需要修改用 全局变量 时,需要用 global 关键字在函数内声明全局变量。例如:
x = 1
def f():
global x # 在函数内声明全局变量
x = 666
y = 777
print(x, y)
f() # 输出 666 777
print(x) # 会发现全局变量x也被修改了
print(y) # 会报错,因为y是局部变量,函数外无法使用
1.5、嵌套定义函数
函数内部也可以定义函数。函数内部定义的函数,作用域为外层函数。例如:
def f():
def g(x): # 定义函数g()
x += 1
print(x)
g(5) # 调用函数g()
f() # 输出6
1.6、pass 语句
当函数定义完但还不想实现时,可以用 pass 占位符,来避免出现语法错误。例如:
def f():
pass
二、参数传递
2.1、值传递
int
、float
、bool
、str
等采用 值传递。值传递 指的是 实参 传递给 形参 的是 数值,而不是 变量空间。
将 实参的 初始值 拷贝给 形参。此时,对形参的改动 不会影响 实参的初始值。例如:
def f(y):
y = 5
print(y)
x = 10
f(x)
print(x) # 会发现x的值没变
2.2、引用传递
列表 采用的就是 引用传递。引用传递 指的是 实参 将自己的 变量空间 传递给了 形参。
将 实参的 引用 传给 形参,此时 对形参的修改 会影响 实参的初始值。例如:
def f(b):
for i in range(len(b)):
b[i] += 1
a = [0, 1, 2, 3, 4]
f(a)
print(a) # 会发现列表a中的每个数加了1
三、return 语句
return
语句终止当前正在执行的函数并将控制权返回到调用该函数的地方,并返回结果。例如:
def f(x):
if x == 1:
return # 不写返回值时,会返回 None
if x == 2:
return 3 # 返回一个变量
if x == 3:
return 4, 5 # 返回多个变量
a = f(1)
b = f(2)
c, d = f(3)
e = f(4) # 没写return时,也会返回None
print(a, b, c, d, e) # 输出 None 3 4 5 None
四、lambda 表达式
lambda
关键字可以创建 匿名函数,目的是为了简化代码。lambda 函数的语法格式如下。其中,arguments
指的是 参数,expression
指的是 函数的返回值 (不用写 return)。
lambda arguments: expression
有些函数可能会 用函数作为参数 (因为函数和变量实际上是一样的),这种情况的 第一种处理方法 就是,先将函数定义出来,然后将函数传进去。例如:
def foo(a, b, g):
g()
return a + b
def f():
print("I'm called!")
s = foo(3, 4, f)
上面第一种处理方法意味着需要占用一个函数名。如果不想占用一个函数名,则可以使用 匿名函数 (lambda),例如:
def foo(a, b, g):
g()
return a + b
s = foo(3, 4, lambda: print("I'm called!"))
匿名函数也可以 传入参数,例如:
def foo(a, b, g):
g(1, 2)
return a + b
s = foo(3, 4, lambda x, y: print("I'm called %d %d!" % (x, y)))
print("s = ", s)
"""output
I'm called 1 2!
s = 7
"""
常与 sort() 函数配合使用,sort() 默认 先根据第一个元素进行比较,再根据第二个元素进行比较,如果希望先根据第二个元素进行比较,且不用 lambda,则需要这样写:
pairs = [[1, "one"], [2, "two"], [3, "three"], [4, "four"]]
def compare(pair):
return pair[1]
pairs.sort(key=compare) # 每个元素使用第二个变量比较大小
print(pairs) # 输出:[[4, 'four'], [1, 'one'], [3, 'three'], [2, 'two']]
我们可以用 lambda 替换 compare
函数:
pairs = [[1, "one"], [2, "two"], [3, "three"], [4, "four"]]
pairs.sort(key=lambda pair: pair[1]) # 每个元素使用第二个变量比较大小
print(pairs) # 输出:[[4, 'four'], [1, 'one'], [3, 'three'], [2, 'two']]
注意,
lambda
不能写return
,直接将返回值写在里面就自动视为return
五、函数递归
在一个函数内部,也可以调用函数自身。这种写法被称为 递归。
写递归函数可以从 集合 的角度来思考。理解递归函数的执行顺序可以用 树 的形式来思考。
例如,求解斐波那契数列第 𝑛 项可以采用如下写法:
def fib(n):
if n <= 2:
return 1
return fib(n - 1) + fib(n - 2)
print(fib(6)) # 输出 8