在使用Scratch编程的时候,我们为了把具有通用价值的积木组合起来,让别的指令调用,会编写“自制积木”。
在上图中,我们定义了一个名字是“求和”的自制积木,它接受两个输入项,并把这两个输入项的值加起来输出。在这个例子中,自制积木的优势并不是很明显,因为我们的程序规模小,逻辑也简单。但如果是一个复杂的程序,我们要多次用到同样的逻辑时,通过自制积木,不仅减少编程的工作量,还能让程序结构清晰易懂。使用自制积木,是实现“模块化编程”的重要方式。以后我们还会讲什么是“模块化编程”,今天我们来谈谈,Python中是怎么实现这种“自制积木”机制的。
Python中的“自制积木”,真名是“自定义函数”。我们就来学习一下函数的知识吧。
一、函数的定义
Python中的函数是一段能够实现特定功能的、可重复使用的语句组合。每个函数都有独特的名字来标识,我们通过名字来调用函数实现它的功能。——实际上,以前我们在Scratch中编程,就是在调用Scratch提供的“函数”——也就是指令积木,你不需要管指令积木内部是怎么实现让小猫说话和移动的,只要你指定说话的内容和步数,它自然就会遵守你的指示行动。如果现有的积木满足不了你的需求,你就可以“自制积木”。
Python中的函数也是一样道理。在前面的编程中,我们使用过print()、input()、int()、float()、sum()等,它们是Python定义好的,类似于Scratch中提供的标准积木,称为“标准函数”,我们可以直接调用它们实现对应的功能而不关心实现细节。例如你在使用print()函数的时候,不用关心为它内部是怎么把你指定的内容按格式输出到控制台的,只要按正确的方式给它传递参数就可以了,这就是函数的方便之处。如果标准函数不满足你的需求,你就可以按照Python的约定,我们可以编写自己的“函数”,供自己和别人的程序调用。
来看一个最简单的自定义函数和调用:
# 定义函数
def say_hello():
name = input('你叫什么名字?')
print('hello,',name)
# 调用函数
say_hello()
在“调用函数”这行注释之前,我们使用def关键字定义了一个函数,名字是say_hello,后面要加上英文半角的括号和冒号。括号中是写参数的,类似于自制积木的时候定义输入项,这个函数我们没有定义要传递的参数,所以是一个空的括号。下面的两行就是函数的代码,它们必须缩进来表示属于这个函数。
函数的名字和变量名字一样都属于标识符,命名时需要遵循一定的规则: – 最好不要用中文,使用英文字母、数字和下划线,不能以数字开头 – 名称能够描述函数的功能 – 名称最好是小写的单词,可以用下划线分隔便于阅读 – 不要与Python内置的标准函数重名
调用函数的时候,就写上函数名加括号,如果有参数,在括号中按顺序写上要传递的参数值就可以了。
需要注意的是,调用函数的代码要写在函数后面,否则Python会找不到你定义的函数。
二、函数的参数与返回值
我们上面定义的say_hello()函数不需要传递参数,称为“无参函数”;而我们使用的print()这类函数就需要传递参数,称为“有参函数”。
如果要定义有参函数,需要在函数名后面的括号里写上参数的名字,用“,”分开。函数可以有多个参数,定义的时候括号中每一个参数叫做“形参”,意思是“形式上的参数”,因为在不调用函数的时候,这些参数并没有数值;而我们在调用的时候,需要按照形参的数量和顺序传递具体的数据过去,这些数据被称为“实参”——就是具有实际值的参数。
在函数内部,我们可以用形参的名字,获得调用的时候传递给它们的数据,进行处理。处理完如果需要告诉调用者一个结果,就可以使用return关键字,把结果“返回”给调用者。
举个例子:
# 定义函数
def add(a, b, c):
num = a + b + c
return num
# 调用函数
a, b, c=1,2,3
result = add(a,b,c)
print(result)
一个函数可以写return也可以不写,如果不写,默认python会返回一个“None”对象,表示什么也没有。函数还可以返回多个结果,用逗号隔开,这样调用者会获得一个由全部返回值构成的元组(就是我们前面和列表一起学习的由小括号包括起来的数据元素集合)。
再举个例子:
# 返回多个值的函数
def get_xy(n):
x = n*2
y = n*3
return x, y
# 调用函数获得元组
result = get_xy(5)
print(result) # 打印出(10, 15)
三、函数的调用
通过前面的例子我们可以看出,只要使用函数名加()就可以调用函数,如果函数有参数,要把参数依次写在括号内,用逗号分开。
另外,函数的定义要在调用之前。上面的例子我们都是先定义函数,下面再调用的。有时代码会混合起来写,比如:
print('hello')
# 返回多个值的函数
def get_xy(n):
x = n*2
y = n*3
return x, y
# 调用函数获得元组
result = get_xy(5)
print(result) # 打印出(10, 15)
这段代码是在前一个示例第一行之前加了一个print()函数的调用,执行你会看到,程序先打印出’hello’,接下来的函数定义代码并不会执行,而是在调用时才执行了函数内容,打印出(10,15)。
函数可以自己调用自己,这称为递归。我们在用Scratch中学习过递归调用,Python函数内部也可以调用函数自己,比如:
# 递归求阶乘的函数
def fac(n):
if n <= 1:
return 1
else:
return fac(n-1)*n # 自己调用自己
print(fac(4))
这是用于求一个数字阶乘的函数,一个数n的阶乘n!=1✕2✕3✕…✕(n-1)✕n。由于除了n=1的时候阶乘为1,大于1时n的阶乘都是n自身再乘以(n-1)!,所以可以用递归的方式来实现这个函数。以上面的代码为例,执行过程如下:
- 调用 fac(4),函数的返回值是4fac(3),由于fac(3)未知,函数产生了一个自己的“克隆体”(也就是一块计算机中的内存空间)来继续计算fac(3);
- 调用fac(3),函数返回值是3fac(2),由于fac(2)未知,函数调用自己继续计算fac(2);
- 调用fac(2),函数返回值是1*fac(1),由于fac(1)未知,函数调用自己继续计算fac(1);
- 调用fac(1),这回函数直接返回了1;
- 1返回给fac(2),fac(2)得到了2;
- 2 返回给fac(3),fac(3)得到了6;
- 6 返回给fac(4),fac(4)得到了24;
- 24 返回给print()函数输出到控制台,程序结束。
想一想,如果没有递归调用,我们要写多长的代码才能得到这个结果啊。
四、常用的标准函数
除了前面使用过的print()、input()等函数,其实python还提供了很多函数供我们使用(目前总计69个),我们今天再学习几个函数:
- abs(x):返回数字的绝对值,正数的绝对值是它本身,负数的绝对值是支掉负号的数值(相反数),0的绝对值是0;
- type(x):这是个很有用的函数,可以返回参数的数据类型。比如class’int’代表整数,class’str’代表字符串,class’list’代表列表等;
- ord(x):返回字符串对应的Unicode编码,Unicode编码是用于把字符串保存在计算机内的二进制数字;比如print(ord(‘a’))就会打印出’a’在计算机内部的编码97;这里的x只能是长度为1的字符串;
- chr(x):返回Unicode编码对应的字符,比如print(chr(97))会打印出字符’a’;
- open():用于打开文件读写数据,比如你可以把成绩列表写入到文件中,这样程序结束之后结果不会丢失,下次程序可以从文件中获得这些数据;这个函数我们用到时再讲;
- sorted(x):当接收一个参数时会将参数中的元素从小到大排列并返回一个列表;可以将reverse参数设置为True来按从大到小排列;
- list(x):把参数转换为列表数据类型,和int()、float()的性质是一样的;
- tuple(x):把其它类型的参数转换为元组;
- set(x):把其它类型的参数转换为集合。
我们来举几个例子:
number = '037965112858'
# 打印['0', '1', '1', '2', '3', '5', '5', '6', '7', '8', '8', '9']
print(sorted(number))
# 打印['9', '8', '8', '7', '6', '5', '5', '3', '2', '1', '1', '0']
print(sorted(number, reverse=True))
# 打印['0', '3', '7', '9', '6', '5', '1', '1', '2', '8', '5', '8']
print(list(number))
# 打印('0', '3', '7', '9', '6', '5', '1', '1', '2', '8', '5', '8')
print(tuple(number))
# 打印{'6', '3', '9', '5', '7', '0', '1', '8', '2'}
print(set(number))
五、课后作业
编写一个自定义函数get_age(x),参数x为身份证号,需要根据身份证号计算并返回年龄。
程序运行时,要求输入姓名和身份证号,然后调用自定义函数计算年龄,输出“XXX,你今年XX岁”。