函数、传参、返回值,和代码复用

函数、传参、返回值,和代码复用

在这一章节中,我们主要学习函数(Function),我们知道,”function” 一词本身就有“功能”的意思,便于理解,可以直接将“函数”视为“功能”。出于严谨,下文中我们仍然统一称之为“函数”。

内置函数

我们之前已经使用过一些函数,如 printinput,它们属于内置函数,BIF(built-in functions),顾名思义,是 Python 自带的一些函数,我们可以直接使用它们。以 print 函数为例,包括但不限于以下的调用形式都是合法的。

1
2
3
4
5
6
7
8
9
10
11
>>> print("hello, world!")
hello, world!
>>> print(1024)
1024
print(6 + 4)
10
>>> print(True)
True
word = "hello"
print(word)
hello

自定义函数

既然存在内置函数,那意味着也存在自定义函数,确实是这样,本章节也围绕自定义函数展开。

定义

一般的,通过 def 关键字定义函数,括号 () 内为其参数 (Param),return 关键字用于返回值。

先来看一个最简单的自定义函数:

1
2
3
def add(a, b): # 不要忽略冒号
result = a + b # 用 result 变量保存参数的和
return result

def 定义了一个函数名为 add 的自定义函数,它有名为 a 和 b 的两个参数,并返回 result 的值。

对于这种逻辑简单的函数,还可以直接写成这样:

1
2
def add(a, b):
return a + b

函数光是定义是永远不会运行的,还需要我们调用:

1
2
3
4
def add(a, b):
return a + b

print(add(4 + 6)) # 10

函数体内还可以做更多的逻辑判断,比如我们实现一个求绝对值的函数:

1
2
3
4
5
6
7
8
9
def abs(a):
if a >= 0:
return a
else:
return -a

print(abs(10)) # 10
print(abs(-8)) # 8
print(abs(0)) # 0

这个函数还可以写成这样:

1
2
3
4
def abs(a):
if a < 0:
a = -a
return a

如果函数不需要返回值,则 return 关键字不是必须的:

1
2
3
4
def greet():
print("Hello!")

greet() # Hello!

在这个问好函数 greet 中,由于不需要传参,所以括号内没有参数。

形参和实参

对于函数的“参数”,还有“形参”和“实参”的概念,即形式参数和实际参数。我们仍然以上文的 abs 函数为例:

1
2
3
4
5
6
7
def abs(a):
if a < 0:
a = -a
return a

number = -10
abs(number) # 10

在这个例子中,abs(number)abs 函数传入了 number 的值,即 -10 现在是 abs 函数的实参;定义时,abs(a) 中的 a 也是参数,但为形参,仅用来代表实际传入的 -10

简单来说,形参的值是不固定的,由传入的实参确定。

明白了这一点后,我们也能理解下面的代码了:

1
2
3
4
5
6
7
8
def fun(a):
a = 10

a = 8
print(a) # 8

fun(a)
print(a) # 8

若让改变变量 a 起效,应这样写:

1
2
3
4
5
6
def fun(a):
return 10

a = 8
a = fun(a)
print(a) # 10

代码复用

自定义函数最常被用作封装功能,便于代码复用。

在上一章节的最后,我们提出前台登录的程序还有很大的改进空间,其中关键的一点就是代码可维护性差。现在,我们用新学的知识继续改进它:

1
2
3
4
5
6
7
8
9
def get_age_from_id():
id = input("请输入你的身份证号:")

while not id.isdigit() or len(id) != 18:
id = input("输入有误,请重新输入身份证号:")

birth_year = int(id[6:10])
age = 2020 - birth_year
return age

我们将从身份证获取年龄的代码抽象出来,封装成一个自定义函数,这样,这样,我们只需要关注业务逻辑部分,而无需在意具体的实现细节:

1
2
3
4
5
6
7
8
9
10
11
12
13
name = input("请输入你的姓名:")
age = get_age_from_id()

if name == "莉莉":
print("小姐里面请!")
elif age > 60:
print("大爷先回家歇歇吧!")
elif age == 40:
print("贡献您,今日消费全免,里面请!")
elif age >= 18: # 当 age 小于等于 60 并且 大于等于 18 时
print("欢迎您的到来,里面请!")
else: # 其余情况
print("小孩子回家玩去")

这样做的好处是很多的。如果我们后面的代码中需要重复使用这个功能,不用每次都拷贝一遍代码,若是需要修改其中的某些细节,也不需要挨个修改。

实战

在上一章节中,我留了一个课后练习题:实现一个猜数字的小游戏。你不知道有练习题?练习题会在编程小窝群中发布,我会挨个批改,帮助大家在实战中精进。

有一个同学交了这样的一份答卷:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import random

given_number = random.randint(0, 9)
input_number = input("请输入您猜的数字:")

while not input_number.isdigit() or len(input_number) > 1:
if not input_number.isdigit():
input_number = input("输入有误,请重新输入:")
else:
input_number = input("输入有误,请输入 0 到 9 之间的个位数:")

input_number = int(input_number)

count = 1

while input_number != given_number:
if input_number > given_number:
input_number = input("猜大了,你已经输错了 %d 次" % count)

while not input_number.isdigit() or len(input_number) > 1:
if not input_number.isdigit():
input_number = input("输入有误,请重新输入:")
else:
input_number = input("输入有误,请输入 0 到 9 之间的个位数:")
input_number = int(input_number)
else:
input_number = input("猜小了,你已经输错了 %d 次" % count)

while not input_number.isdigit() or len(input_number) > 1:
if not input_number.isdigit():
input_number = input("输入有误,请重新输入:")
else:
input_number = input("输入有误,请输入 0 到 9 之间的个位数:")
input_number = int(input_number)

count += 1

print("猜测正确")

本来是很简单的一个功能,写了这么一大坨,这也难怪,因为他当时还不会使用自定义函数,现在我们着手改进它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import random


def get_number():
number = input("请输入您猜的数字:")

while not number.isdigit() or len(number) > 1:
if not number.isdigit():
number = input("输入有误,请重新输入:")
else:
number = input("输入有误,请输入 0 到 9 之间的个位数:")

return int(number)


given_number = random.randint(0, 9)
input_number = get_number()

count = 1

while input_number != given_number:
if input_number > given_number:
print("猜大了,你已经输错了 %d 次" % count)

input_number = get_number()
else:
print("猜小了,你已经输错了 %d 次" % count)

input_number = get_number()

count += 1

print("猜测正确")

是不是一下子就简洁了许多呢? 👏

扩充功能

函数非常灵活,我们可以通过传入多个参数扩充功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def get_id():
id = input("请输入身份证号:")

while not id.isdigit() or len(id) != 18:
id = input("输入有误,请重新输入身份证号:")

return id


def get_info_from_id(id, info):
if info == "age":
birth_year = int(id[6:10])
return 2020 - birth_year
elif info == "from":
return id[0:6]
elif info == "sex":
sex = int(id[-2])
if sex % 2 == 0: # 为偶数时
return "女"
else:
return "男"


id = get_id()
print(id)

print("年龄:", get_info_from_id(id, "age"))
print("性别:", get_info_from_id(id, "sex"))
print("出身地编号:", get_info_from_id(id, "from"))

小结

利用自定义函数,对代码进行封装,代码更加简洁,并且业务逻辑部分与技术实现部分相解耦,降低我们组织代码时的心智负担,编写更具有可读性,并且高度可维护的代码。

函数非常灵活,功能也无比强大。在今后的代码编写中,要多加思考,是否可以利用函数优化代码。