一、函数的定义
在Python中,定义了一个函数使用def语句,一次写出函数名、括号、中括号的参数和冒号:,然后在缩进快中编写函数体,函数的返回值用return语句进行返回。
我们以自定义一个求绝对值的my_abs(),并对其进行函数调用,例:
def my_abs(x):
if x >= 0:
return x
else :
return -x
num = 15
print(my_abs(num))
请注意,函数体内部的语句在执行时一旦遇到了return时,函数逻辑机就执行完毕并将结果返回。因此函数内部通过条件判断和循环可以实现非常复杂的逻辑。
如果没有return语句,函数执行完毕后也会返回结果,只是结果为None。return None可以简写为return。
return 语句的后面如果有变量或者值,则函数存在返回值,那么可以将函数赋值给一个变量。
在函数名的括号内写的变量被称为函数参数,函数参数可有可无。在python我们的参数有实参和形式参数(实参)之分,对函数定义时的函数名括号内的参数被称作形式参数,函数调用时函数名括号内的参数被称作实参,该参数必须是实际存在的。
二、函数的多个返回值
在我们Python中,函数的返回值只有一个,如果我们非要返回多个值,python解释器会将所有的返回值封装为一个元祖(tuple)数据类型进行返回。在语法上返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数的多返回值就是一个tuple,只是写起来更加方便。
def fun(list_tmp):
max_num = max(list_tmp)
min_num = min(list_tmp)
avg_num = sum(list_tmp)/len(list_tmp)
return max_num , min_num , avg_num
list_num = [10,3,7,2,8]
tmp = fun(list_num)
print(tmp,type(tmp))
输出 :
(10, 2, 6.0) <class 'tuple'>
由此可见,返回值只能是一个值,当有多个返回值时,python解释器会将所有的返回值封装为一个tuple进行返回,依旧做到了,函数返回值只有一个。
二、函数的形参类型
python中函数的形参右下面几种,必选参数,默认参数,可变参数,关键字参数。
(1)必选参数
如果一个函数(或方法、过程、自定义函数等)带有一个或多个参数,那么你在调用这个函数时也必须带有相同数量的参数,否则就会提示“必选参数”的错误。
def add(x, y, z):
return x + y + z
print(add(2,3,4))
输出:
9
上面代码中,x,y,z 就是形参中的必选参数,我们的add(x,y,z)不论在什么地方调用时,总是需要三个实参。=,少一个都不可以。
(2)默认参数
如果一个函数在定义的时候,并对其参数进行了赋值,那么就说这个参数是该函数的一个默认参数,函数调用时,默认参数可以不用使用实参进行传值,会使用在函数定义时赋给的值。
#函数功能:x的y次方
def mypow(x, y=2):
return x ** y
print(mypow(9)) #函数调用时没有给形参y赋值,因此y默认等于2
print(mypow(4,3)) #函数调用时对形参x,y都进行了赋值,y不在使用默认值,使用实参传给的值
在定义函数时,我们需要将默认参数放在必选参数的后面,否则python就会报错。当函数有多个参数是,把变化大的参数放在前面,变化小的参数放在后面,变化下的参数就可以作为默认参数。
使用默认参数最好的就是帮助我们降低了函数调用的难度。我们在使用默认参数时应该注意list类型的默认参数。
当我们使用可变数据类型作为函数参数时,我们会出现如下错误
例1:
def fun(tmp = []):
tmp.append('Hello')
return tmp
list_num = []
print(fun(list_num))
print(fun(list_num))
输出:
['Hello']
['Hello', 'Hello']
例2:
def fun(tmp = {4,3,2,6}):
tmp.pop()
return tmp
print(fun())
print(fun())
输出:
{3, 4, 6}
{4, 6}
这是因为Python函数在定义时,默认参数tmp的值就被计算出来,即[ ],它是一个可变的数据类型,因为默认参数tmp也是一个变量,它指向对象[ ] ,如果改变了L的内容,则下次调用时,默认参数的内容就会发生改变,不再是函数定义时的 [ ]了
所以我们在定义默认参数时要牢记:默认参数必须执行不变对象。像上面的例子,我们可以None这个对象来实现。
使用不变对象作为函数参数,不变对象一旦创建,对象内部的数据就不能被修改,这样就减少了由于修改数据导致的错误,由于对象不变,多任务的环境下同时读取对象就不需要加锁,同时一点问题也没有。
(3)可变参数
在python中,还可以定义可变参数,可变参数就是传入的参数的个数是可变的,可以是0~n任意个参数,定义一个函数时,我们必须确定输入的参数,如果参数不确定,将多个实参作为一个list或tuple传入函数。但是这样在我们调用该函数时需要对该函数的实参进行组装,变为一个list或tuple。
如果我们使用可变参数对函数定义,那么我们在函数调用时就不用将多个实参变为list或tuple,可以直接输入多个实参。
def add1(*number): #该函数使用可变参数
sum = 0
for num_tmp in number:
sum += num_tmp
return sum
def add2(number): #该函数没有使用可变参数
sum = 0
for num_tmp in number:
sum += num_tmp
return sum
print(add1(1,2,3,5)) #add1() 函数可以传入多个实参
print(add2([1,2,3,5])) #add2() 函数只能传一个参数,如果传多个实参,需要对实参进行组装
输出:
11
11
定义可变参数和定义list或tuple相比,仅仅在参数前面加了一个 * 号。但在函数内部,number接收的是一个tuple,因此函数代码完全不变。
我们可以在add2(*number)函数中添加print(type(number)),来看看结果:
def add1(*number):
print(type(number))
sum = 0
for num_tmp in number:
sum += num_tmp
return sum
print(add1(1,2,3,5))
输出:
<class 'tuple'>
11
我们发现number在加了 * 号后变成了一个元组数据类型。
如果我们已经有了一个元组或list,要调用一个带有可变参数的函数怎么办?
python 允许你在实参list或tuple前面添加一个 * 号,这样就把list或tuple的元素变成可变参数传进去。
def add1(*number):
print(type(number))
sum = 0
for num_tmp in number:
sum += num_tmp
return sum
list_tmp = [1,2,3,5]
print(add1(1,2,3,5))
print(add1(*list_tmp))
输出:
<class 'tuple'>
11
<class 'tuple'>
11
(4)关键字参数
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
def fun(**kwargs):
print(kwargs,type(kwargs))
fun(a=1,b=2,c=3)
输出:
{'a': 1, 'b': 2, 'c': 3} <class 'dict'>
如果我们已经有了一个dict类型的变量,那么我们调用含有关键字参数的的函数时需要,将dict类型的数据当做实参传给形参时,我们需要dict前面加 * 然后再讲该dict转为关键字参数传进去。
dict_tmp ={'a':1,'b':2,'c':2}
def fun(**kwargs):
print(kwargs,type(kwargs))
fun(**dict_tmp)
(2)参数组合
在python 中定义函数,可以使用必选参数、默认参数、可变参数和关键字参数,这四种参数都可以一起使用,或者只使用其中某些,但是注意,参数定义的顺序必须是:必选参数,默认参数,可变参数,和关键字参数。
对于任意函数都可以通过func(*args,**kwargs)的形式去调用它,无论它的形参时如何定义的。
三、函数的练习
第一题:
对于一个十进制的整数,定义f(n)为其个位数字的平方和,如:
第一行包含3个整数k,a,b,k>=1 ,a,b<=10**18 ,a<=b;
输出:输出对应的答案。
示例 :
输入: 51 5000 10000
输出: 3
#其个位数字的平方和
def f(n):
res = 0
for item in str(n):
res += int(item) ** 2
return res
#判断是否满足k*f(n) == n
#满足 返回True 否则返回False
def isOk(k, n):
if k * f(n) == n:
return True
else:
return False
def main():
str1 = input('输入:')
list1 = str1.split()
print(list1)
k = int(list1[0])
a = int(list1[1])
b = int(list1[2])
count = 0
for i in range(a, b + 1):
if isOk(k, i):
count += 1
print(count)
main()
第二题:
编写一个名为collatz()的函数,它有一个名为number的参数。如果参数是偶数,那么collatz()就打印出number//2,并返回该值。如果number是奇数,collatz()就打印并返回3*number+1。然后编写一个程序,让用户输入一个整数,并不断对这个数调用collatz(),直到函数返回值1(令人惊奇的是,这个序列对于任何整数都有效,利用这个序列,你迟早会得到1!既使数学家也不能确定为什么。你的程序在研究所谓的“Collatz序列”,它有时候被称为“最简单的、不可能的数学问题”)。3
输出:
10
5
16
8
4
2
1
def collatz(number):
if number%2 ==0:
print(number//2)
return number//2
else:
print(3*number+1)
return (number * 3) + 1
def main():
number = int(input("Num:"))
number = collatz(number)
while number!=1:
number=collatz(number)
pass
main()
四、函数的参数检测
我们在使用一些函数时,如果传入的参数不符合函数的要求,我们的程序有可能会报错,我们可以在向函数传递实参的时候,看一下函数的说明,看看函数需要什么样的参数。我们在定义一个函数的时候,如果这个函数比较复杂,我们会写函数说明,以便在调用的时候帮助我们。def add(x:int, y:int)->int: #变量名:数据类型 这样子也是函数说明中的一部分。
"""
add: sum x and y
:param x: int,float,.....
:param y: int,float.....
:return: int
"""
if isinstance(x,(int,float,complex)) and isinstance(y,(int,float,complex)):
return x + y
else:
print("Error")
定义一个如上的函数,""" """之间的内容就是我们的函数说明,我们还用的了isinstance(x,type)函数,进行变量类型检测。
使用help(add) 我们的看到函数说明如下:
Help on function add in module __main__:
add(x:int, y:int) -> int
add: sum x and y
:param x: int,float,.....
:param y: int,float.....
:return: int
这样,我们就可以通过函数说明,正确的调用函数了