一、函数的定义
在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这样,我们就可以通过函数说明,正确的调用函数了