函数形参类型有四种:位置参数、默认参数、可变参数、关键字参数。其中只有位置参数是必传的
位置参数
即按照参数的位置来进行传参,比如说下面的my函数,name和sex就是位置参数,位置参数是必传的,
def my(name,sex): # 位置参数,调用时必填,否则报错 ..... return name;
1 # 定义时指定传入参数为字符串和字典,但实际调用时不必非传入字符串和字典 2 def my4(s:str,d:dict): #s和d不一定非要传字符串和字典类型 3 print(s) 4 print(d) 5 6 my4(123,'abc') #123 abc
#位置参数在调用的时候就要传几个参数,且顺序必须和定义时一一对应,否则就会报错了,那如果有多个位置参数的话,记不住哪个位置传哪个了怎么办,可以使用位置参数的名字来指定调用 def db_connect(ip,user,password,db,port): print(ip) print(user) print(password) print(db) print(port) db_connect(user='adf',ip='2342',password='dadf',db=1,port='3036') #这种赋值方式不用和定义函数时的参数顺序一一对应,这种调用方式叫关键字传参 db_connect('4567','2342',password='dadf',db=1,port='3036') #前面没有指定的就按照默认的参数顺序赋值 混搭时,位置参数必须放在前面 db_connect(password='dadf',db=1,port='3036','4567','2342') #语法错误 混搭时,位置参数必须放在前面
默认参数
在定义形参的时候,给函数默认赋一个值,比如说数据库的端口这样的,默认给它一个值,这样就算你在调用的时候没传入这个参数,它也是有值的。所以,默认参数不是必填的,如果给默认参数传值的话,它就会使用你传入的值,否则使用默认值。
如果使用默认值参数的话,默认值参数必须放在位置参数后面定义。
# 默认值参数,非必填 port=3306 如果调用的时候不传,port=3306 传的话就是传入的值 def db_connect(ip,port=3306): print(ip,port) db_connect('118.24.3.40') #118.24.3.40 3306 db_connect('118.24.3.40','3307') #118.24.3.40 3307
1 #同时实现文件读和写的函数 2 # dic默认为None,只传文件名就读,文件名和dic都传则写 读的时候需return返回值,写的时候不用 3 import json 4 def op_file_tojson(file_name,dic=None): 5 if dic: #dic不为空,写 6 with open(file_name,'w',encoding='utf-8') as fw: 7 json.dump(dic,fw) 8 else:#dic为空,读 9 with open(file_name, encoding='utf-8') as f: 10 content = f.read() 11 if content: 12 res= json.loads(content) 13 else: 14 res = {} 15 return res
非固定参数:
上面的两种位置参数和默认参数都是参数个数是固定的,如果一个函数,参数不是固定的,也不知道以后这个函数会扩展成啥样,可能参数越来越多,这个时候如果再用固定的参数,那后面程序就不好扩展了,这时候就可以用非固定参数,非固定参数有两种,一种是可变参数,一种是关键字参数。
可变参数
可变参数用*来接收,后面想传多少个参数就传多少个,如果位置参数、默认值参数、可变参数一起使用的的话,可变参数必须在位置参数和默认值参数后面。可变参数也是非必传的。
#可变参数,参数组 # 1.不是必传的 # 2.把传入的元素全部都放在一个元组里面 # 3、不限传入参数个数 # 4、它用在参数比较多的情况下 def send_sms(*args): print('发报警短信',args) #1、不传参数 send_sms() #发报警短信 () #2、传一个参数 send_sms(67865) #发报警短信 (67865,) #3、传N个 send_sms(345345,4656,89766) #发报警短信 (345345, 4656, 89766)
关键字参数
关键字参数使用**来接收,后面的参数也是不固定的,想写多少个写多少个,当然也可以和上面的几种一起来使用,如果要一起使用的话,关键字参数必须在最后面。
使用关键字参数的话,调用的时候必须使用关键字传参。关键字参数也是非必传的。
#关键字参数 # 1.不是必传的 # 2、不限制参数个数 # 3.把传入的元素以key:value 的形式全部都放在一个字典里面 def send_sms2(**kwargs): print(kwargs) send_sms2() #{} send_sms2(name='xiaohei',sex='nan') #{'sex': 'nan', 'name': 'xiaohei'} send_sms2(addr='湖北',country='china',work='coding') #{'country': 'china', 'work': 'coding', 'addr': '湖北'}
四种参数类型一起用时,赋值顺序必须是:1、位置参数 2、默认值参数 3、可变参数 4、关键字参数
def my(name,country='China',*args,**kwargs): #1、位置参数 2、默认值参数 3、可变参数 4、关键字参数 print(name) print(country) print(args) print(kwargs) my('xiaojun','America','zhuhai','武汉',color='green',age=13) my('xiaojun','zhuhai','武汉',color='green',age=13) my('xiaojun','zhuhai','武汉',color='green',age=13) my('xiaojun','武汉',color='green',age=13) my('xiaojun',color='green',age=13)
函数返回值
为什么函数要返回值呢,是因为在这个函数操作完之后,它的结果在后面的程序里面需要用到。
每个函数都有返回值,如果没有在函数里面指定返回值的话,在python里面函数执行完之后,默认会返回一个None,函数也可以有多个返回值,如果有多个返回值的话,会把返回值都放到一个元组中,返回的是一个元组。
函数中的返回值使用return,函数在遇到return就立即结束。
return有两个作用:
1、结束函数,只要函数里面遇到return,函数立即结束运行
2、返回函数处理的结果
def my2(): for i in range(50): return i print(my2()) #返回0 第一次循环i=0,遇到return 函数结束运行
#return时可以同时返回多个值,如果有多个返回值的话,会把返回值都放到一个元组中,返回的是一个元组。 def my3(): a=1 b=2 c=3 return a,b,c b,c,d =my3() #调用my3()返回值分别赋给b、c、d s=my3() #将返回值全都赋给一个变量,则返回的是一个元组,取值时需根据下标来去 print(b,c,d) #1 2 3 print(s) # (1, 2, 3) 返回的是一个元组 print(type(s)) #<class 'tuple'>
递归调用
递归调用的特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
#递归就是函数自己调用自己 #如果没有指定结束条件,递归最多递归999次 #递归可以实现和循环同样的效果,但是递归的效率没有循环高,尽量不要使用递归 def say(): global count count +=1 print('say') print(count) say() say() #调用say() 报错 RecursionError: maximum recursion depth exceeded while calling a Python object def test1(): num = int(input('please enter a number:')) if num%2==0: #判断输入的数字是不是偶数 return True #如果是偶数的话,程序就退出了,返回true print('不是偶数请重新输入!') return test1() #如果不是偶数的话继续调用自己,输入值 print(test1()) #调用test