python自定义函数学习二
一、参数的变化
1、位置参数
位置参数,就是在传递参数值时,必须和函数定义的参数一一对应,位置不能打乱。
如:两个固定参数的自定义函数调用
def test(name,age):
print("姓名%s,年龄%s"%(name,str(age)))
test('Hai',11)
test(11,'Hai')
# 结果为:
# 姓名Hai,年龄11 #正确的结果
# 姓名11,年龄Hai #错误的结果
位置参数的值传递方式是一种最常用的方法。
2、关键字参数
主要是避免传递值出错,提供了一种“参数名=值”的方式,在调用函数时显示表示,而且无需考虑参数位置顺序。
如:
def test(name,age):
print("姓名%s,年龄%s"%(name,str(age)))
test(name='Tim',age=20) #所有参数都由“参数名=值”的方式指定
test(age=20,name='Tim') #关键字参数指定时,可以不考虑位置对应顺序
test('Tim',age=20) #部分指定时,左边可以不指定,从右边指定开始
# test(name='Tim',20) #将出错,不支持左边指定,右边不指定的方式
# test(age=20,'Tim') #出错
结果为:
姓名Tim,年龄20
姓名Tim,年龄20
姓名Tim,年龄20
3、默认值
参数预先指定为默认值,当没有给该参数传值时,该参数自动选择默认值。
def test(name='',age=20):
print('姓名%s,年龄%s'%(name,str(age)))
test(19) #默认情况下是给第一个默认的参数赋值
test()
test("Tim",18)
# 结果为
# 姓名19,年龄20
# 姓名,年龄20
# 姓名Tim,年龄18
4、不定长参数
Python允许程序员编写不定长参数,方便函数调用时,根据实际情况传递值的数量。
1)传递任意数量的参数值
格式:函数名([param1,param2,…,]*paramX) 带(“ * ”)的paramX参数,可以接收任意数量的值。但一个自定义函数只能有一个带“ * ”的参数,而且只能放置最右边的参数中,否则自定义函数执行时将报错。
如:
def melon(name,*att):
print(name)
print(type(att)) #打印出att的类型
s=''
for i in att:
s+=' '+i
print(s)
melon('西瓜','甜','圆形') #调用自定义函数,任意参数传入两个值
# 结果为:
# 西瓜
# <class 'tuple'> #为元组类型
# 甜 圆形
2)传递任意数量的键值对
格式:函数名([param1,param2,…,]**paramX)
带 ** 的paramX参数用法与带 * 的用法类似,区别是传递的是键值对。
如:
def melon(name,**att):
print(name)
print(type(att))
return att
print(melon("西瓜",taste='甜',shape='圆形',color='绿色'))
# 执行结果
# 西瓜
# <class 'dict'> att参数实际为字典类型
# {'taste': '甜', 'shape': '圆形', 'color': '绿色'}
二、传递元组,列表和字典值
自定义参数可以传递元组,列表,字典值
def melon(name,att):
print(name)
print(type(att))
return att
#传递元组
get1=melon('西瓜',('甜','圆','绿色'))
print(get1)
# 执行结果
# 西瓜
# <class 'tuple'>
# ('甜', '圆', '绿色')
# #传递列表
get2=melon('西瓜',['甜','圆','绿色'])
print(get2)
#执行结果
# 西瓜
# <class 'list'>
# ['甜', '圆', '绿色']
#传递字典
att1={'taste':'甜','shape':'圆','color':'绿色'}
get3=melon('西瓜',att1)
print(get3)
#执行结果
# 西瓜
# <class 'dict'>
# {'taste': '甜', 'shape': '圆', 'color': '绿色'}
自定义函数传递列表和字典后的问题
在自定义函数内获取从参数传递过来的列表,字典对象后,若在函数内部对它们的元素进行变动,则会同步影响到函数外部传递前的变量的元素。
如:
def Fruit(name,att):
att[0]=att[0]*0.8
return att
att_L=[20,'甜','圆形','绿色'] #设20为价格
get1=Fruit('西瓜',att_L) #调用函数,返回修改后的列表
print(get1) #打印返回的列表对象
print(att_L)#打印原始列表对象
# 执行结果:
# [16.0, '甜', '圆形', '绿色']
# [16.0, '甜', '圆形', '绿色']
我们在自定义函数体内修改了所传递的列表对象的元素后,这里是修改了价格,函数体外面的列表对象att_L的值也被同步修改了。这可能是不希望发生的。
在函数中,列表对象直接传递导致函数体外列表对象同步变化的现象,证明了传递列表(和字典)其实传递的是内存里同一个地址的对象,当函数体里修改这个传入对象值时,函数体外面的对象自然也跟着变化。
解决的办法:采用复制列表(字典)对象方法进行避免
def Fruit(name,att):
att[0]=att[0]*0.8
return att
att_L=[20,'甜','圆形','绿色'] #设20为价格
get2=Fruit('西瓜',att_L.copy()) #利用copy()的方法实现对象的复制
print(get2)
print(att_L)
# 执行结果为:
# [16.0, '甜', '圆形', '绿色']
# [20, '甜', '圆形', '绿色']
函数传递对象总结:
可以把传递的对象分为不可变对象,可变对象。数字,字符串,元组属于不可变对象,列表,字典属于可变对象。
不可变对象:在函数里进行值修改,会变成新的对象(内存中产生新的地址)
可变对象:在函数里进行值修改,函数内外还是同一个对象,但是值同步发生变化。