1 实验介绍
1.1 关于本实验
复杂的问题通常采用“分而治之”的思想解决,把大任务分解为多个小的任务,解决每个小的容易的子任务,从而解决较大的复杂任务。主要介绍函数的声明和调用、返回值及函数的四种参数,以及两类特殊的函数等相关知识。
1.2 实验目的
理解函数的作用;熟练掌握函数定义和函数调用的规则和用法;掌握函数参数传递的规则和用法;lambda函数;理解函数的嵌套和递归调用。
2 函数的声明和调用
2.1 函数声明
函数是可重复使用的,用来实现单一或相关联功能的代码段。函数能提高代码的重复利用率。Python提供了许多内建函数,如print()等。用户自已创建的函数称为用户自定义函数,语法格式如下。
def <函数名> ([<形参列表>]):
[<函数体>]
说明:
(1)函数使用关健字def(define的缩写)声明,函数名为有效的标识符和圆括号()。
(2)任何传入参数和自变量必须放在圆括号中间,圆括号之间用于定义参数。
(3)函数内容以冒号起始,并且缩进。
(4)函数名下的每条语句前都要用Tab键缩进,没有缩进的第一行则被视为在函数体之外的语句,与函数同级的程序语句。
(5)return[表达式]结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回None。
【任务1】函数声明
hello是函数的名称,后面的括号里是参数,这里没有,表示不需要参数。但括号和后面的冒号都不能少。
def hello():
print("Hello Word!")
hello()
程序运行结果如下:
Hello Word!
2.2 函数调用
在Python中,函数调用的语法格式为:
函数名([实际参数])
函数调用时传递的参数是实参,实参可以是变量、常量或表达式。当实参个数超过一个时,用逗号分隔,实参与形参应在个数、类型和顺序上一一对应。对于无参函数,调用时实参为空,但()不能省略。
【任务2】利用海伦公式,求三角形面积。
import math
def triarea(x,y,z):
s = (x + y + z)/ 2
print(math.sqrt((s - x) * (s - y) * (s - z) * s) )
triarea(3,4,5)
程序运行结果如下:
6.0
2.3 函数返回值
函数返回值是指函数被调用执行后,返回给主调函数的值。一个函数可以有返回值,也可以没有返回值。使用关键字return实现,形式如下。
return 表达式
return语句使得程序控制从被调用函数返回到调用函数,并将返回值带回。
(1)在函数内根据具体的return语句返回。
【任务3】求两个数中的较大值
def max(a,b):
if a>b:
return a
else:
return b
t=max(3,4)
print(t)
程序运行结果如下:
4
(2)如果没有return语句,会自动返回None;如果有return语句,但是return后面没有表达式,也返回None。
【任务4】没有return 语句举例
def add(a,b):
c=a+b
t=add(3,4)
print(t)
程序运行结果如下:
None
(3)如果需要从函数中返回多个值时,可以使用元组作为返回值。
【任务5】返回多个值
def getMaxMin(a):
max=a[0]
min=a[0]
for i in range(0,len(a)):
if max<a[i]:
max=a[i]
if min>a[i]:
min=a[i]
return(max,min)
a_list=[4,8,3,0,-3,93,6]
x,y=getMaxMin(a_list)
print("")
print("最大值为",x,"最小值为",y,)
程序运行结果如下:
最大值为 93 最小值为 -3
3 参数传递
3.1 实参与形参
实参(实际参数)是指传递给函数的值,即在调用函数时,由调用语句传给函数的常量、变量或表达式。形参(形式参数)是在定义函数时,函数名后面括号中的变量,用逗号分隔。作为函数与主调程序交互的接口,用来按收调用该函数时传递的实参,从主调程序获得初值,或将计算结果返回给主调程序。
形参和实参具有以下特点:
(1)函数在被调用前,形参只是代表了执行该函数所需要参数的个数、类型和位置,并没有具体的数值,形参只能是变量,不能是常量、表达式。只有当调用时,主调函数将实参的值传速给形参,形参才具有值。
(2)形参只有在被调用时才分配内存单元,调用结束后释放内存单元,因此形参只在函数内部有效,函数调用结束返回主调用函数后则不能再使用该形参变量。
(3)实参可以是常量、变量、表达式、函数等,无论实参是何种数据类型的变量,函数调用时必须是确定的值,以便把这些值传给形参。
(4)实参和形参在数量、类型、顺序方面应严格一致,否则会发生类型不匹配错误。
3.2 传对象引用
Python的参数传递与C语言不同,既不是传值(pass-by-value),也不是传引用(pass-by-reference),而是传对象引用(pass-by-object-reference),传递的是一个对象的内存地址。这种方式相当于传值和传址的一种综合。当函数收到的是可变对象(如字典或者列表)的引用,就能修改对象的原始值-----相当于“传引用”。当函数收到的是不可变对象(如数字、字符或者元组)的引用,就不能直接修改原始对象-----相当于“传值”。
【任务6】数字和列表实例
import sys
a=2
b=[1,2,3]
def change(x,y):
x=3
y[0]=4
change(a,b)
print(a,b)
程序运行结果如下:
2 [4, 2, 3]
数字作为一个不可变对象,a的值没有变化,而b作为列表对象,是可变对象,所以b被改变了。
【任务7】字符串和字典实例
import sys
a="11111"
b={"a":1,"b":2,"c":3}
def change(x,y):
x="222"
y["a"]=4
change(a,b)
print(a,b)
程序运行结果如下:
11111 {‘a’: 4, ‘b’: 2, ‘c’: 3}
a作为字符串是不可变对象,所以没有变化;b作为字典是可变对象,所以被改变了。
3.3 参数分类
Python的参数分为必备参数、默认参数、关键参数和不定长参数等。
3.3.1必备参数
必备参数是指调用函数时,参数的个数、参数的数据类型,以及参数的输入顺序必须正确,否则会出现语法错误。需要在printme()输入数字语法才正确。
【任务8】必备参数实例
def printme(str):
print(str)
return
printme('Hello,World!')
Hello,World!
3.3.2 默认参数
默认参数是指允许函数参数有默认值,如果调用函数时不给参数传值,参数将获得默认值。Python通过在函数定义的形参名后加上赋值运算符(=)和默认值,给形参指定默认参数值。注意,默认参数值是一个不可变的参数。
【任务9】使用默认参数值
def say(message, times = 1):
print(message * times)
#调用函数
say('Hello') #默认参数times为1
say('World', 4)
程序运行结果如下:
Hello
WorldWorldWorldWorld
3.3.3 关键参数
函数的多个参数值一般默认从左到右依次传入。但是,Python也提供了灵活的传参顺序,引入了关键参数。关键参数又称为命名参数,用于改变指定参数的顺序。
【任务10】使用关键参数
def func(a, b=4, c=10):
print('a is', a, 'and b is', b, 'and c is', c)
#调用函数
func(3, 7)
func(24, c=24)
func(c=40, a=100)
程序运行结果如下:
a is 3 and b is 7 and c is 10
a is 24 and b is 4 and c is 24
a is 100 and b is 4 and c is 40
3.3.4 不定长参数
不定长参数又称为可变长参数,参数以一个号开头代表接收元组,以两个号开头代表接收字典。
【任务11】可变长参数实例
def foo(x,*y,**z):
print(x)
print(y)
print(z)
foo(1,2,3,a="a",b="b")
程序运行结果如下:
1
(2, 3)
{‘a’: ‘a’, ‘b’: ‘b’}
4 两类特殊函数
4.1 匿名函数
匿名函数是指lambda表达式,不使用def定义函数,所有使用lambda函数的地方都可以使用普通函数(def声明的函数)来代替,语法如下。
lambda parameters:expression
参数如下:
parameters:可选,通常是以逗号分隔的变量表达式。
expression:条件表达式,不能包含人分支或循环,也不能包含return函数。
【任务12】lambda函数实例
sum = lambda arg1, arg2: arg1 + arg2
# 调用sum函数
print ("相加后的值为 : ", sum( 10, 20 ))
程序运行结果如下:
相加后的值为 : 30
4.2 递归函数
【任务13】计算4的阶乘
两种方法如表计算阶乘所示,方法一通过循环语句来计算阶乘,该方法的前提是了解阶乘的计算过程,并可用语句把计算过程模拟出来。方法二通过递推关系将原来的问题缩小成一个规模更小的同类问题,将4的阶乘转换为3的阶乘问题,只需找到4的阶乘和3的阶乘之间的递推关每亩,以此类推,直到在某一规模上(当n为1时)问题的解已知,其后回归,这种解决问题的思想称为递归。
表 计算阶乘
方法一 | 方法二 |
---|---|
循环 | 递归 |
s=1 for i in range(1,4): s=s*1 print(s) | def fac(n): if n==1: return 1 return n*fac(n-1) |
递归简结、清晰、可读性强,但执行效率低。
【任务14】列表元素个数的加权和
输入一个嵌套列表,嵌套层次不限,根据层次,求列表元素的加权个数和。第一层每个元素算一个元素,第二层每个元素算两个元素,第三层每个元素为三个元素,第四层每个元素算第四个元素,…,以此类推。
输入格式:
在一行中输入一个列表。
输也格式:
在一行中输出加权元素个数值。
输入样例:
在这里给出一组输入,例如:
[1,2,[3,4,[5,6],7],8]
输出样例:
在这里给出一组输入。例如:
15
代码如下。
def f(a,b):
s=0
for i in a:
if isinstance(i,list):
s=s+f(i,b+1)
else:
s=s+b
return s
s=eval(input(""))
r=f(s,1)
print(r)
程序运行结果如下:
[1,2,[3,4,[5,6],7],8]
15
【任务15】斐波那契数列
斐波那契(Fibonacci)数列又称为黄金分割数列,其值为1,1,2,3,5,8,13,21,…。
(1)方法一:递归
递归函数Fib()代码如下:
def fib(n):
if n==0:
return 1
if n==1:
return 1
if n>1:
return fib(n-1)+fib(n-2)
def fib_recursion(n):
return[fib(i) for i in range(0,n)]
num=fib_recursion(5)
print(num)
程序运行结果如下:
[1, 1, 2, 3, 5]
(2)方法二:递推
Fib递推代码如下:
def fib_loop(n):
result_list=[]
a,b=0,1
while n>0:
result_list.append(b)
a,b = b,a+b
n-=1
return result_list
num=fib_loop(5)
print(num)
程序运行结果如下:
[1, 1, 2, 3, 5]