python函数
函数用于在程序中分离不同的任务;函数允许程序的控制在调用代码和函数代码之间切换
函数功能
(1)实现结构化程序设计。通过把程序分割为不同的功能模块,可以实现自顶向下的结构化设计
(2)减少程序的复杂度。简化程序的结构,提高程序的可阅读性
(3)实现代码的复用。一次定义多次调用,实现代码的可重用性
(4)提高代码的质量。实现分割后子任务的代码相对简单,易于开发、调试、修改和维护
(5)协作开发。大型项目分割成不同的子任务后,团队多人可以分工合作,同时进行协作开发
(6)实现特殊功能。递归函数可以实现许多复杂的算法
函数分类
-
(1)内置函数。Python语言内置了若干常用的函数,例如abs()、len()等等,在程序中可以直接使用
-
(2)标准库函数。Python语言安装程序同时会安装若干标准库,例如math、random等等。通过import语句,可以导入标准库,然后使用其中定义的函数
-
(3)第三方库函数。Python社区提供了许多其他高质量的库,如Python图像库等等。下载安装这些库后,通过import语句,可以导入库,然后使用其中定义的函数
-
(4)用户自定义函数。本章将详细讨论函数的定义和调用方法
函数声明与调用
语法:
def 函数名(参数1,参数2......):
函数体
【例1】函数创建示例1:定义返回两个数平均值的函数
def my_average(number1, number2):
return (number1+number2)/2
【例2】函数创建示例2:定义打印n个星号的无返回值的函数
def print_star(n):
print(("*"*n).center(50)) #打印n个星号,两边填充空格,总宽度50
思考
Q:函数创建示例3:定义计算并返回第n阶调和数(1 + 1/2 + 1/3 + … + 1/n)的函数
R:参考答案:
def harmonic(n): #计算n阶调和数(1 + 1/2 + 1/3 + … + 1/n)
total = 0.0
for i in range(1, n+1):
total += 1.0 / i
return total
函数调用
语法:
函数名([实参列表])
示例:基于思考题声明的函数进行调用
#因为有返回值,所以可以通过声明变量进行赋值或者直接print输出即可
get_result=harmonic(10) #则表示的hi计算1+1/2+......+1/10
print(get_result)
参数的传递
形式参数和实际参数
-
声明函数时所声明的参数,即为形式参数,简称形参
-
调用函数时,提供函数所需要的参数的值,即为实际参数,简称实参
-
【例1】形式参数和实际参数示例(my_max1.py)
def my_max1(a, b): #此处声明的a,b则为形式参数
if a > b: print(a, '>', b)
elif a == b: print(a, '=', b)
else: print(a, '<', b)
my_max1(1, 2) #此时调用函数传入的1,2为实际参数
x = 11; y = 8
my_max1(x, y) #此处的x,y也为实际参数
my_max1(1) #因为要求传入a,b两个位置参数,此时只传入一个参数则会报错,缺少一个参数b
传递不可变对象引用
如果函数体中修改对象的值,其结果实际上是创建了一个新的对象
【例1】传递不可变对象的引用示例(inc1.py):错误的递增函数
i=100
def inc(j,n):
j += n
inc(i,10)
print(i)
i的初始值为100,当调用函数inc(i,10)后,在函数体内,执行了"i+=10"语句,在函数体内的i编程了110.但是,当函数调用完毕返回主程序,i的值仍然为100,因为整数i是不可变对象,而在Python语言中,一个函数不能改变一个不可变对象(例如:整数、浮点数、布尔值或字符串的值)的值(即函数无法产生副作用)
思考
Q:如何对传递不可变对象例题1实现正确的递增函数
R:参考结果:
i=100
def inc(j,n):
j += n
return j
i =inc(i,10)
print(i)
传递可变对象引用
调用函数时,如果传递的是可变对象(例如:list对象)的引用,则函数体中可以直接修改对象的值
【例1】传递可变对象引用的函数示例1:定义一个可以交换给定列表中两个指定下标的元素值的函数
def exchange(a, i, j):
temp = a[i]
a[i] = a[j]
a[j] = temp
可选参数
在声明函数时,如果希望函数的一些参数是可选的,可以在声明函数时为这些参数指定默认值调用该函数时,如果没有传入对应的实参值,则函数使用声明时指定的默认参数值
【例1】可选参数示例(my_sum1.py):基于期中成绩和期末成绩,按照指定的权重计算总评成绩
def my_sum1(mid_score, end_score, mid_rate = 0.4): #期中成绩、期末成绩、期中成绩权重 #基于期中成绩、期末成绩和权重计算总评成绩
score = mid_score * mid_rate + end_score * (1 - mid_rate)
print(format(score, '.2f')) #输出总评成绩,保留2位小数
my_sum1(88, 79) #期中成绩权重为默认的40%
my_sum1(88, 79, 0.5) #期中成绩权重设置为50%
位置参数和命名参数
-
函数调用时,实参默认按位置顺序传递形参。按位置传递的参数称之为位置参数
-
函数调用时,也可以通过名称(关键字)指定传入的参数,例如:my_max1(a=1, b=2); my_max1(b=2, a=1)
-
按名称指定传入的参数称为命名参数,也称之为关键字参数。使用关键字参数具有三个优点:参数按名称意义明确;传递的参数与顺序无关;如果有多个可选参数,则可以选择指定某个参数值
-
在带星号的参数后面声明的参数强制为命名参数,如果这些参数没有默认值,且调用时必须使用命名参数赋值,则会引发错误
-
如果不需要带星号的参数,只需要强制命名参数,则可以简单地使用一个星号
可变参数
-
在声明函数时,通过带星的参数,如* param1,允许向函数传递可变数量的实参。调用函数时,从那一点后所有的参数被收集为一个元组
-
在声明函数时,也可以通过带双星的参数,如** param2,允许向函数传递可变数量的实参。调用函数时,从那一点后所有的参数被收集为一个字典
-
带星或双星的参数必须位于形参列表的最后位置
【例1】可变参数示例1(my_sumVarArgs1.py)。利用带星的参数计算各数字累加和
def my_sum3(a, b, *c): #各数字累加和
total = a + b
for n in c:
total = total + n
return total
print(my_sum3(1, 2)) #计算1+2
print(my_sum3(1, 2, 3, 4, 5)) #计算1+2+3+4+5
print(my_sum3(1, 2, 3, 4, 5, 6, 7)) #计算1+2+3+4+5+6+7
函数返回值
-
return语句和函数返回值
-
【例1】函数的返回值示例(my_max.py)。编写函数,利用return语句返回函数值,求若干数中的最大值
def my_max(a, b, *c): #求若干数中的最大值
max_value = a #假设第一个数为最大值
if max_value < b: #如果最大值小于b,则b为最大值
max_value = b
for n in c: #循环迭代c中每个元素n,如果最大值小于n,则n为最大值
if max_value < n:
max_value = n
return max_value #利用return语句返回最大值
#测试代码
print(my_max(1, 2)) #求(1, 2)中的最大值
print(my_max(1, 7, 11, 2, 5)) #求(1, 7, 11, 2, 5)中的最大值
多条return语句
-
return语句可以放置在函数中任何位置,当执行到第一个return语句时,程序返回到调用程序
-
【例1】判断素数(prime.py)。先编制一个判断一个数是否为素数的函数,然后编写测试代码,判断并输出1~99中的素数
def is_prime(n):
if n < 2: return False #如果n小于2,返回False
i = 2
while i*i <= n:
#一旦n能够被2~ 中的任意整数整除,n就不是素数,返回False
if n % i == 0: return False
i += 1
return True
#测试代码
for i in range(100): #判断并输出1~99中的素数,以空格分隔
if is_prime(i):print(i, end=' ')
变量作用域
-
全局变量、局部变量和类型成员变量
-
全局变量:在一个源代码文件中,在函数和类定义之外声明的变量
-
全局变量的作用域为其定义的模块,从定义的位置起,直到文件结束位置
-
通过import语句导入模块,也可以通过全限定名称“模块名.变量名”访问。或者通过from…import语句导入模块中的变量并访问
-
【例1】全局变量定义示例(global_variable.py)
TAX1 = 0.17 #税率常量17%
TAX2 = 0.2 #税率常量20%
TAX3 = 0.05 #税率常量5%
PI = 3.14 #圆周率3.14
-
【例2】全局变量、局部变量
num = 100 #全局变量
def f():
num = 105 #局部变量
print(num) #输出局部变量的值
#测试代码
f();
print(num)
全局语句global
在函数体中,可以引用全局变量,但如果函数内部的变量名是第一次出现且在赋值语句之前(变量赋值),则解释为定义局部变量
【例1】函数体错误引用全局变量的示例
m = 100
n = 200
def f():
print(m+5) #引用全局变量m
n += 10 #错误,n在赋值语句前面,解释为局部变量(不存在)
#测试代码
f()
非局部语句nonlocal
在函数体中,可以定义嵌套函数,在嵌套函数中,如果要为定义在上级函数体的局部变量赋值,可以使用nonlocal语句,表明变量不是所在块的局部变量,而是在上级函数体中定义的局部变量。nonlocal语句可以指定多个非局部变量。例如nonlocal x, y, z
【例1】非局部语句nonlocal示例
def outer_func():
tax_rate = 0.17 #上级函数体中的局部变量
print('outer func tax rate =', tax_rate) #输出上级函数体中局部变量的值
def innner_func():
nonlocal tax_rate #不是所在块的局部变量,而是在上级函数体中定义的局部变量
tax_rate = 0.05 #上级函数体中的局部变量重新赋值
print('inner func tax rate =', tax_rate) #输出上级函数体中局部变量的值 innner_func() #调用函数
print('outer func tax rate =', tax_rate) #输出上级函数体中局部变量的值(已更改)
\
递归函数
自调用函数,在函数体内部直接或间接地自己调用自己,即函数的嵌套调用是函数本身
【例1】使用递归函数实现阶乘
def factorial(n):
if n == 1: return 1
return n * factorial(n - 1)#测试代码
for i in range(1,10): #输出1~9的阶乘
print(i,'! =', factorial(i))
递归函数的原理
-
每个递归函数必须包括如下两个主要部分。
-
(1)终止条件。表示递归的结束条件,用于返回函数值,不再递归调用。例如,factorial()函数的结束条件为“n等于1”。
-
(2)递归步骤。递归步骤把第n步的参数值的函数与第n-1步的参数值的函数关联。例如,对于factorial(),其递归步骤为“n * factorial(n-1)”
-
例如,调和数的计算公式为:Hn = 1 + 1/2 + . . . + 1/n 故可以使用递归函数实现:
-
(1)终止条件:Hn = 1 #当n==1时
-
(2)递归步骤:Hn = Hn-1 + 1/n #当n>1时每次递归,n严格递减,故逐渐收敛于1。
思考
Q:使用递归函数计算最大公约数(gcd.py)
R:参考答案
number1=int(input("请输入一个数:"))
number2=int(input("请输入另一个数:"))
def gcd(p, q): #使用递归函数计算p和q的最大公约数
if q == 0: return p #如果q=0,返回p
return gcd(q, p % q) #否则,递归调用gcd(q, p % q)
#测试代码
print(gcd(number1, number2)) #计算并输出p和q的最大公约数
课后练习
1.以下内容关于函数描述正确的是?
A、函数用于创建对象
B、函数可以让重新执行的更快
C、函数是一段代码用于执行特定的任务
D、以上说法都是正确的
2. x = True
def printLine(text):
print(text, ' Runoob')
printLine('Python')
以上代码输出结果为?
A、Python
B、Python Runoob
C、text Runoob
D、Runoob
3. 如果函数没有使用 return 语句,则函数返回的是?
A、0
B、None 对象
C、任意的整数
D、错误! 函数必须要有返回值。
4.def greetPerson(*name):
print('Hello', name)
greetPerson('Runoob', 'Google')
以上代码输出结果为?
A、Hello Runoob Hello Google
B、Hello ('Runoob', 'Google')
C、Hello Runoob
D、错误!函数只能接收一个参数。
5. 关于递归函数描述正确的是?
A、递归函数可以调用程序的使用函数。
B、递归函数用于调用函数的本身。
C、递归函数除了函数本身,可以调用程序的其他所有函数。
D、Python 中没有递归函数。
6. result = lambda x: x * x
print(result(5))
以上代码输出结果为?
A、lambda x: xx
B、10
C、25
D、55
7. def Foo(x):
if (x==1):
return 1
else:
return x+Foo(x-1)
print(Foo(4))
以上代码输出结果为?
A、10
B、24
C、7
D、1
8. 如果我们需要从 math 模块中输出 pi 常量,以下代码正确的是?
A、print(math.pi)
B、print(pi)
C、from math import pi print(pi)
D、from math import pi print(math.pi)
9. 以下哪个符号用于从包中导入模块?
A、.
B、*
C、->
D、,
10. numbers = [1, 3, 6]
newNumbers = tuple(map(lambda x: x , numbers))
print(newNumbers)
以上代码输出结果为?
A、[1, 3, 6]
B、(1, 3, 6)
C、[2, 6, 12]
D、(2, 6, 12)
需要了解更多可关注以下公众号,每日更新一篇测试文章