目录呀
参数传递
- 不可变类型
- 可变类型
参数类型
- 位置参数
- 关键字参数
- 默认参数
- 不定长参数
- 混合参数
关于解包
参数传递
不可变类型
Python中的数值(int float)、字符串、元组在作为参数进行传递的时候,传递的仅仅是变量的值(即值传递),不会对变量本身有任何影响。比如 fun_1( invariant ),传递的只是变量 invariant 的值,没有影响变量 invariant 本身。如果在 fun_1( invariant ) 内部修改 invariant 的值,只是修改另一个复制的对象,不会影响 invariant 本身。
# 例如下
invariant =100
def fun_1(invariant): #一般情况下不会让形参名跟其他变量名一样,这里只为演示
invariant +=10
print(invariant )
fun_1(invariant)
print(invariant)
# 110
# 100 即 全局变量invariant 和 形参invariant 并非是一个变量
# 也可以利用 id() 函数直接返回两个变量的地址,也会发现不一样
可变类型
Python中的列表,集合,字典类型在作为参数进行传递时,在函数内部对其形参变量的改变会影响到函数外部的变量(即引用传递)。如 fun_2( variable ),则是将 variable 真正的传过去,在函数内部对其进行修改后函数外部的变量 variable 也会发生相应的变化。
# 例如下
variable = [1,2,3,4,5]
def fun_2(L):
L[2]+=2 #在函数内部改变列表元素的值
print(L)
fun_2(variable)
print(variable) #我没会发现外边的变量也被改变了
# [1, 2, 5, 4, 5]
# [1, 2, 5, 4, 5]
参数类型
位置参数
位置参数就是普通的参数,在函数调用时,传入实参的数量必须和定义的形参数量一致,实参传入的值按顺序一一传给形参。
定义方法:def fun_3(name_1,name_2...):
# 例如下
def fun_3(name_1, name_2):
print("{0} like {1}".format(name_1,name_2))
fun_3("I","learning")
# I like learning
关键字参数
对于函数 fun_3,如果你在传入参数时弄错了,写成了 fun_3( “learning”, “I”)。那么他就会输入“learning like I”,这显然不是我们想得到的。那么有没有一种参数,即使我们写错了参数的顺序,也能让我得到正确的结果呢? 关键字参数就是这样的一种参数。
关键字参数与必备参数不同,它是按照关键字(即形参名)来传递的。在函数调用时必须明确的给某一个参数传递确定的值。比如 fun_4( name_1 = “I”, name_2 = “you”)。
定义方法:def fun_4( *, name_1, name_2...):
优点:不用考虑参数传递的顺序。
# 例如下
def fun_4(*, name_1, name_2): # * 号后面全是关键字参数
print("{0} like {1}".format(name_1,name_2))
fun_4(name_2 = "learning",name_1 = "I") #调用时必须明确给形参传递的值,否则会报错
# fun_4("I","learning") #错误的调用方式,会报错
# I like learning
其实,必备参数也能当做关键字参数来用,但是要注意的是如果只把部分参数当做关键字来用,那就必须让关键字参数处于参数列表的后边。
# 例如下
def summation(num1, num2, num3):
print(num1 + num2 + num3)
summation(2,num3=1,num2=3) # 调用时把后两个参数当做关键字参数来用
# 6
默认参数
默认参数,顾名思义,即参数有一个默认值。在给参数传入实参值时,该参数的值就是实参值,在没有给参数传入实参时,该参数的值就是默认值。
定义方式:def fun_5( age, n = 2...):
。其中形参 n 叫做默认参数。
def fun_5( age, n = 2):
print(age**n)
fun_5(2) # 平常我们用这个函数求一个数的平方,那么只需要传入一个实参
fun_5(2,3) # 但有时候我们还可以用这个函数求一个数的 n 次方,那么就要传入两个参数
# 4
# 8
注意:多次调用函数且没有给默认参数传递实参时,默认参数只在第一次调用时进行解释。那么使用列表、字典这样可变类型的默认参数,就有可能导致逻辑错误。
# 例如下
def lpush( age, L = []):
L.append(age) # 向列表中插入元素
print(L)
lpush(1) # 我们是想输出 [1]
lpush(2) # 我们是想输出 [2]
lpush(3) # 我们是想输出 [3]
# 实际输出结果
# [1]
# [1, 2]
# [1, 2, 3]
# 显然这跟我们预想的不一样。
'''
造成错误的原因是默认参数具有记忆性,如果你连续多次调用而不给默认参数传递值时,默认参数就会保留上一次调用的结果。
# 修正方法
def lpush( age, L = None): # None表示空,主要作用是用来占位
if L == None : # 如果没有给默认参数传递值
L = [] # 则将其赋值成空表
L.append(age) # 向列表中插入元素
print(L)
lpush(1)
lpush(2)
lpush(3)
# [1]
# [2]
# [3]
不定长参数
上面说的那几中参数类型都属于定长参数,即定义了几个形参,最多就只能传入几个实参,下面要说的,就是可以传入无限多个实参的参数类型。当你不确定传入参数的具体个数时,就可以使用这样的形参类型。
1. 单星号元组参数
将传入的参数序列打包成一个元组(tuple)传入形参,进而引用元组的元素,以达到传入并引用任意多个
参数的目的。
定义方式:def fun_6(*args):
。要注意区分与关键字参数定义方式的区别。
# 例如下
def fun_6(*args): # n个数求和
nsum = 0
for i in args: # 此时的args是一个元组,其元素就是传入的参数序列
nsum+=i
print("{0}的和是{1}".format(args,nsum))
fun_6(1,2,3,4)
fun_6(1,2,3,4,5)
(1, 2, 3, 4)的和是10
(1, 2, 3, 4, 5)的和是15
2. 双星号字典参数
将任意多个赋值方式与关键字参数一样的参数打包成一个字典(dict),通过引用字典的元素从而达到传入
并引用任意多个个参数的目的。双星号字典参数往往运用到关键字参数。相比于关键字参数,它的优点是可以
传入任意多个参数,而且关键字不用事先定义。
定义方式:def fun_7(**kwargs):
# 例如下
def fun_7(**kwargs):
for k,v in kwargs.items():
print( k, ":", v)
fun_7(name = "阿珍", sex = "女", hobby = "阿强")
# name : 阿珍
# sex : 女
# hobby : 阿强
混合参数
混合参数指的是当以上所讲的参数类型中两个或两个以上一起使用时的参数情况。当这种情况出现时,参数类型的定义需要遵守一定的先后顺序。否则就会出现故障。比如当关键字参数和双星号字典参数混用时,传进了一个实参,那么是个实参的值到底是传给关键字参数,还是打包传入字典呢?
为了解决这个问题,Python制定了一套规则,即混用参数必须要满足:位置参数参、默认参数、单星号元组参数、关键字参数、双星号字典参数的顺序。
传参顺序:非关键词参数,先依次传给位置参数和默认参数,剩下的都传给单星号元组参数(单星号元组参数就是打包它们吃剩下的…)。关键字参数,先传给关键字参数,剩下的双星号字典参数打包。
def fun_8(name,age = 2,*args, hobby, **kwargs):
# 本例的关键字参数 hobby 没有使用(*,hobby)的定义方法,因为用的话就会报错...
# 默认参数也可以放在 单星号元组参数后面,但是那样的话它就不能接收实参传的值了(都被元组打包了)
print("name:{}".format(name))
print("age:",age)
print("cellpn:",args)
print("hobby:{}".format(hobby))
print(kwargs)
fun_8("阿珍",18, 1,3,2,3,3,8,5,0,5,0,3, hobby = "阿强", sex = "女" )
'''
输出结果:
name:阿珍
age: 18
cellpn: (1, 3, 2, 3, 3, 8, 5, 0, 5, 0, 3)
hobby:阿强
{'sex': '女'}
'''
关于解包
对于含有多个位置参数的函数,我们在进行实参传递的时候可以事先把所有的实参打包成一个可迭代对象(list、tuple、 set、dict),然后依次传入。系统会在函数内自动把打包的参数解包依次传递给相应的形参。例如下
def fun_9(v1, v2, v3, v4):
print(v1 + v2 + v3 + v4)
L = [1, 2, 3, 4] # 把实参打包成一个列表
fun_9(1, 2, 3, 4 ) # 可以这样用
fun_9(*L) # 也可以这样用
# * 表示解包符,即告诉系统需要解包
# 10
# 10