函数(⼀)参数传递之位置参数关键字参数默认参数可变长度参数序列解包函数
参数,函数添加函数说明⽂档
⼀、参数传递机制
根据实际参数的类型不同,参数传递⽅式可分为 2 种:值传递和引⽤(地址)传递
1、值传递:适⽤于实参类型为不可变类型(字符串、数字、元组);
2、引⽤/地址传递:适⽤于实参类型为可变类型(列表,字典);
def demo(obj):
obj += obj
print("形参值为:",obj)
print("-------值传递-----")
a ="C语⾔中⽂⽹"
print("a的值为:",a)
demo(a)
print("实参值为:",a)
print("-----引⽤传递-----")
a =[1,2,3]
print("a的值为:",a)
demo(a)
print("实参值为:",a)
运⾏结果为:
-------值传递-----
a的值为: C语⾔中⽂⽹
形参值为: C语⾔中⽂⽹C语⾔中⽂⽹
实参值为: C语⾔中⽂⽹
-----引⽤传递-----
a的值为:[1,2,3]
形参值为:[1,2,3,1,2,3]
实参值为:[1,2,3,1,2,3]
值传递和引⽤传递的区别是
函数参数进⾏值传递后,若形参的值发⽣改变,不会影响实参的值;⽽函数参数继续引⽤传递后,改变形参的值,实参的值也会⼀同改变。⼆、参数指定⽅式
1、位置参数:按位置指定 ,实参和形参数量必须⼀致
函数调⽤时括号中只写各个实参,这时形参的值与实参按照顺序⼀⼀对应
在调⽤函数,指定的实际参数的数量,必须和形式参数的数量⼀致(传多传少都不⾏)
2、关键字参数:按形参名字显⽰指定,使⽤形式参数的名字来确定输⼊的参数值。
在函数调⽤时显⽰指定形参(函数定义时的参数)与实参的对应关系 :形参=实参
通过此⽅式指定函数实参时,不再需要与形参的位置完全⼀致,只要将参数名写正确即可。
这是函数调⽤时 形参的值与实参的先后顺序⽆关
def add(x,y):
print('x=',x)
print('y=',y)
#按位置指定
add(2,3)
add(3,2)
#形参名字显⽰指定
add(x=2,y=3)
add(y=3,x=2)
运⾏结果
按位置指定与顺序有关
x=2
y=3
x=3
y=2
形参名字显⽰指定与位置⽆关
x=2
y=3
parameter是什么意思啊
x=2
y=3
3、默认参数:参数指定默认值
在调⽤函数时如果不指定某个参数,Python 解释器会抛出异常。为了解决这个问题,Python 允许为参数设置默认值,即在定义函数时,直接给形式参数指定⼀个默认值。这样的话,即便调⽤函数时没有给拥有默认值的形参传递参数,该参数可以直接使⽤定义函数时设置的默认值。
注意:指定有默认值的形式参数必须在所有没默认值参数的最后,否则会产⽣语法错误。
参数指定默认值之后在函数调⽤时 实参可以只给出没有指定默认值的那些参数 若所有参数都在形参中给出,默认值不⽣效。
def add(x,y=0):
print('x=',x)
print('y=',y)
add(2)
add(3,2)
运⾏结果
x=2
y=0
x=3
y=2
4、可变长度参数
两种形式:函数定义时在参数名前加1个*或2个**
(1)*parameter⽤来接受多个实参并将其放在⼀个元组中
d⽆论调⽤该函数时传递了多少实参,⼀律将其⾃动放⼊元组中
>>>def demo(*p):
print(p)
>>> demo(1,2,3)
(1,2,3)
>>> demo(1,2)
(1,2)
(2)**parameter接受多个关键字参数并存放到字典中
调⽤函数时⾃动将接受的参数转换为字典,注意实参此时需要是关键字参数
>>>def demo(**p):
for item in p.items():
print(item)
>>> demo(x=1,y=2,z=3)
运⾏结果:
('x',1)
('y',2)
('z',3)
注意可变长度参数是在函数定义时通过星号来实现
在函数定义中增加⼀些外围的检查代码,可以防⽌⽤户调⽤函数时传⼊⽆效参数。
def demo(a,b,**kwargs):
for para in kwargs.keys():
if para not in('x','y','z')
raise Exception('{0}is not a valid parameter'.format(para))
print(a+b+sum(kwargs.values()))
# 只能接收'x','y','z',这三个参数
5、传递的参数是序列解包
(1) 关于序列解包
Python列表、元组、集合、字典以及其他可迭代对象,Python解释器可⾃动进⾏解包
对字典使⽤时默认是对字典“键”进⾏操作
对“键:值” 对进⾏操作使⽤字典的items()⽅法
对“值”进⾏操作应使⽤ values() ⽅法进⾏指定
列表
>>> lt =[1,2,3]
>>> a, b, c = lt
>>>print(a,b,c)
123
元组
>>> x, y, z =1,2,3
>>>print(x,y,z)
123
>>> a_tuple=tuple(range(3))
>>> x,y,z = a_tuple
>>>print(x,y,z)
012
字典
>>> s ={'a':1,'b':2}
>>> a,b = s
>>> a
'a'
>>> a,b = s.items()
>>> b
('b',2)
>>> a,b = s.values()
>>> a
1
字符串
>>> a,b,c='ABC'
>>> a
'A'
(2)序列解包逆运算:⾃动⽣成列表
序列解包逆运算⾃动⽣成列表
>>> a,*b, c =1,2,3,4,5
>>> a,b,c
(1,[2,3,4],5)
>>> a,*b,c=tuple(range(20))
>>> b
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
>>> a,*b=1,2,3
>>> b
[2,3]
>>>*b,=1,2,3全部进⾏逆运算赋值号左边最后需要有逗号
>>> b
[1,2,3]
解包星号在赋值号右边
字典使⽤两个星号**进⾏解包
列表元组集合range等使⽤⼀个星号*解包
解包后若进⾏⾃动封装,⾃动封装成元组
若要封装成集合或者字典⼿动添加{},若要封装成列表⼿动添加[]
区别于上述序列解包逆运算(星号在赋值号左边)形成的是列表
>>> s=1,*[2,3,4],*(5,6)#⾃动封装成元组
>>> s
(1,2,3,4,5,6)
>>>a =1,2,3,4
>>>a
(1,2,3,4)
>>> s=*[1,2,3],#只有⼀个元素赋值号右边最后必须要有逗号
>>> s
(1,2,3)
>>>print(*[1,2,3],4,*(5,6))
123456
>>>*range(3),3#⾃动封装成元组
(0,1,2,3)
>>>{*range(3),3,4}#⼿动动封装成集合
{0,1,2,3,4}
>>>{'a':1,**{'b':2}}#⼿动动封装成字典
{'a':1,'b':2}
>>>[*range(1,5)]#⼿动动封装成列表
[1,2,3,4]
>>> s=[*range(1,5)]
>>> s
[1,2,3,4]
(3)函数调⽤时传递的是序列解包
区别上述函数定义时定义可变长参数
⼀般来说函数调⽤实参采⽤序列解包 和函数定义采⽤可变长参数相结合才⽐较好因为在函数定义是我们并不知道实参的长度,不知道序列解包后得到多少个元素
>>>def demo(a,b,c):
...print(a,b,c)
...
传递列表的序列解包
>>> seq =[1,2,3]
>>> demo(*seq)
123
字典⼀个星号解包默认是对间keys()解包
>>> seq ={1:'a',2:'b',3:'c'}
>>> demo(*seq)
123
虽然seq是⼀个字典但是我们的实参是字典的values()的序列解包是⼀个dict_values类型对该dict_values进⾏解包得到的是tuple类型因此只⽤⼀个星号
>>> demo(*seq.values())
a b c
>>> dic={'a':1,'b':2}
>>> t=dic.values()
>>> t
dict_values([1,2])
>>>type(t)
<class'dict_values'>
>>> s=*t,
>>> s
(1,2)
>>>type(s)
<class'tuple'>
使⽤⼀个星号进⾏字典解包传递参数时不要求字典的键和形参名字⼀样如(‘aa’和‘a’)但是个数必须⼀样(都是3个元素)
>>> dic={'aa':1,'bb':2,'cc':3}
>>> demo(*dic)
aa bb cc
>>>> dic={'aa':1,'bb':2}
>>> demo(*dic)
Traceback (most recent call last):
File "<stdin>", line 1,in<module>
TypeError: demo() missing 1 required positional argument:'c'
实参字典两个星解包->关键字参数