函数:
函数的定义和函数的调用不是一回事,程序执行时,遇到定义函数,只会执行定义函数名处,里面的函数体这个时候是不会执行的;
只有到调用函数处才会执行里面的函数体;
返回值:
没有返回值: 无 return; -----返回None
只有 return;----返回None
return None----返回None
有返回值: 可以返回任意数据类型;
返回多个值时,可以用多个变量接收,但是变量要对应,不多不少;或者只用一个变量接收也可以;
参数
定义函数处的参数为形参,形参可以包括位置参数和关键字参数(又称默认参数)且位置参数必须在关键字参数之前;
调用函数处的参数为实参,实参也包括位置参数和关键字参数,位置参数在前,关键字参数在后;
并且上述两种参数都可以只用位置参数,或者只使用关键字参数,当混用时需要满足位置参数在前的原则;
def func(a,b): #形参仅使用位置参数; print(a+b) func(1,2) #实参采用位置参数,一一对应 a=1;b=2 func(1,b=2) #位置参数和关键字参数同时使用,位置参数在前; func(b=1,a=2) #使用关键字参数,可以不按形参顺序赋值;
def func(a,b=2): #形参同时使用位置参数和关键字参数,位置参数在前; print(a+b) func(1,2) #实参采用位置参数,一一对应 a=1;b=2 func(1,b=4) #位置参数和关键字参数同时使用,位置参数在前; func(b=1,a=2) #使用关键字参数,可以不按形参顺序赋值;
def func(a=3,b=2): #形参使用关键字参数; print(a+b) func(1,2) #实参采用位置参数,一一对应 a=1;b=2 func(1,b=4) #位置参数和关键字参数同时使用,位置参数在前; func(b=1,a=2) #使用关键字参数,可以不按形参顺序赋值;
也就是不管定义时形参采取什么样的参数形式,调用时实参可以采用上述三种方式;
动态参数-- *args ----传入的值被当成tuple处理(按照位置参数)
定义时采用动态参数 *args 调用时可以传无数个参数,但是需要按照位置参数进行传递;
比如我们想计算很多个数的和,可能计算三个数,也可能计算100个数,,,
def func(*args): sum=0 for i in args: sum+=i print(sum) func(1,2,3,4) #需按照位置参数进行传递 func(2,3,4,5,6,7,8)
动态参数*args 和位置参数,关键字参数放一起时的顺序:位置参数,*args ,关键字参数;
def func(a,*args,b=10): sum=0 for i in args: sum+=i print(sum+a-b) func(1,2,3,4,b=2) # 传递进去时a被赋值为1,而2,3,4 传给了动态参数args,b的值采用关键字参数赋值为2 func(2,3,4,5,6,7,8) # 传递进去时a被赋值为2,而3,4,5,6,7,8 传给了动态参数args,b的值采用默认值10
动态参数-- **kwargs-----传入的值当成字典处理(按照关键字参数)
def func(**kwargs): #动态参数**kwargs,传入的值当成字典处理 print(kwargs) func(a=1,b=2,c=3)
当位置参数,动态参数*args,关键字参数,动态参数**kwargs同时存在时:
def func(a,*args,b=2,**kwargs): #位置参数,动态参数*args,关键字参数,动态参数**kwargs print(a) print(args) #传入args的值被当成list; print(b) print(kwargs) #传入**kwargs的值被当成字典 func(1,2,3,4,5,b=7,c=9,d=2) # 1->a; 2,3,4,5-->args; 7---->b c:2,d:9----> kwargs; func(1,2,3,4,5,c=8,d=9) # 1->a; 2,3,4,5-->args; 2(默认)(而不是前面的5)---->b c:2,d:9----> kwargs;
运行结果:
顺序:位置参数,动态参数*agrs,关键字参数,动态参数**kwargs
调用函数处使用* 和**: 将tuple或者字典打散;(定义函数处再将其重新组合)
def func(*args): sum=0 for i in args: sum+=i print(sum) nums=[1,2,3,4,5] func(nums[0],nums[1],nums[2],nums[3],nums[4]) func(*nums)
相当于调用函数处将nums列表的元素打散之后传给动态参数*args,定义函数处,将打散的数再重新组合乘一个tuple
再来看调用函数处使用** 将字典打散:
def func(**kwargs): print(kwargs) dic={'a':1,'b':2,'c':3} func(**dic)
如果定义函数处参数的值是一个可变数据类型,每次函数调用不传参数,则会一直共用这个可变数据类型的资源!!!
之前一直没搞懂的问题,现在终于懂了:
def func(L=[]): #使用的默认参数的值是一个可变数据类型list L.append(1) print(L) func() #L=[1] func([]) #L=[1] #因为现在调用函数自己传了一个参数[] 不是原来的列表(已经在[]的基础上append了一个1) func() #L=[1,1] #使用的仍然是默认参数的值-->可变list 还是使用的原来那个list,也就是地址没变,但是list值变了,func()--->L=[1],还是,现在又增加了一个1--->[1,1] fun() #L=[1,1,1] 经过上面两个func()后默认参数还是指向原来的list,只不过这个list会变,不停的append
再举一个例子,仍然是定义函数处使用的默认参数的值为可变数据类型:
形参中的默认参数是可变数据类型,实参不传参,则始终操作的都是同一个数据类型(可变),所以默认参数这个可变数据类型的值是会发生改变的!!!
def func(k,dic={}): # 位置参数k,关键字参数dic 是一个可变数据类型:字典 dic[k]='value' print(dic) func(1) #传的位置参数1赋值给k 作为字典的键, 值为value--->dic={1:'value'} func(2) #字典仍使用默认参数,使用原来那个地址,但是这个字典不再是空的了,因为它会变化!--dic={1:'value',2:'value'} func(3) #dic={1:'value',2:'value'3,'value'}