python中函数参数问题小究

python3中函数参数有位置参数、命名关键字参数、默认参数、非关键字可变长参数、关键字可变长参数几种。

一、位置参数

位置参数是函数的标准参数,是最常用的一种参数格式。定义函数时,由于每个参数都有自己的位置,如果不加以特殊说明,调用函数时,函数就会根据所赋参数的位置来给函数内参数赋值。

def s(x,y):
    print('x=',x)
    print('y=',y)

a,b=1,0
s(a,b)

运行结果:
x= 1
y= 0

调用时,函数会自动将处在x位置的a参数赋给x,把参数b赋给y。

位置参数是必选参数,调用函数时,位置参数未赋值,函数将报错。

二、命名关键字参数

格式:
def s(x,y,*,z,k)
  print('x=',x)
  print('y=',y)
  print('z=',z)
  print('k=',k)
a,b,c,d=4,3,2,1
s(a,b,k=c,z=d)

输出
x= 4
y= 3
z= 1
k= 2

此时,位置参数必须在最前,关键字参数在后,关键字参数之间可以不按顺序。

定义命名关键字参数时,需要使用*分割符,*后面的参数都是命名关键字参数。命名关键字参数在使用时,必须使用‘形参=’这种格式,不然将会报错

三、默认参数

默认参数是指在定义函数时,赋给该参数一个值。调用该函数时,如果未给该参数赋值,则函数会自动将定义时的值拿来使用。


def s(x,k='233'):
print('x=',x)
print('k=',k)

a,b,c,d=4,3
s(a)
s(a,b)
s(a,k=c)
输出:
x= 4
k= 233
x= 4
k= 3
x= 4
k= 4
可以看到,如果省略了k,则默认为是233,如果给k赋值,则以赋值为准。给k赋值时,可以采用位置参数的方式(不加想形参名字),也可以采取关键字参数的方式。
默认参数在定义时的位置必须在位置参数之后。调用的时候,也必须在位置参数之后,否则会报错。这是因为函数在给参数赋值的时候,会优先将值赋给位置参数,剩下如果有多余的值会再赋给默认参数,如果没有就采用默认值。
 

 注意,定义默认参数一定是不可变参数。如果是可变参数,可能会出现一些错误。参考廖雪峰老师微博:

先定义一个函数,传入一个list,添加一个END再返回:

def add_end(L=[]):
    L.append('END')
    return L
当你正常调用时,结果似乎不错:
>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']

当你使用默认参数调用时,一开始结果也是对的:

>>> add_end()
['END']

但是,再次调用add_end()时,结果就不对了:

>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

很多初学者很疑惑,默认参数是[],但是函数似乎每次都“记住了”上次添加了'END'后的list。

原因解释如下:

Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

 定义默认参数要牢记一点:默认参数必须指向不变对象!

要修改上面的例子,我们可以用None这个不变对象来实现:

def add_end(L=None):
    if L is None:
        L = []
    L.append('END')
    return L

现在,无论调用多少次,都不会有问题:

>>> add_end()
['END']
>>> add_end()
['END']

为什么要设计strNone这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。

 
如果函数中既有命名关键字参数,又有默认参数,两个参数必须都在位置参数之后。如果赋值时,默认参数赋值不使用‘k=’这样的格式,则必须严格按照定义函数时的位置来传递参数。如果使用‘k=’这种格式,在这两只参数在传递时位置没有特殊的要求。
但是在定义函数时,如果将默认参数放在命名关键参数之后,则表明这个参数既是默认参数,也是命名关键参数。
def s(x,k=233,*,y,z,j=111):
    print('x=',x)
    print('y=',y)
    print('z=',z)
    print('k=',k)
    print('j=',j)

a,b,c,d=4,3,2,1
s(a,z=c,y=b,k=d)
输出:
x= 4
y= 3
z= 2
k= 1
j=111

四、非关键字可变长参数

非关键字可变长参数用 *变量名  来表示,定义函数时,一般用 *args 来表示。主要用来处理一些不能确定有多少个参数的问题。

函数将多余的不带关键字的参数打包成为一个元组,进行处理。*args后面的参数必须使用关键字,不然全都会被当成可变长参数,被打包到元组中。

但是,*args与默认参数之间顺序的问题也需要注意。


def s(x,y=233,*args):
print('x =',x)
print('y =',y)
for index,i in enumerate(args):
print('args[%s] = %s'%(index,i))
print(type(args))

s(1,2,3,4,5)

输出:

x = 1
y = 2
args[0] = 3
args[1] = 4
args[2] = 5
<class 'tuple'>



可以看到,该函数第一个值赋给位置参数,第二个值赋给默认参数,后面的值全都打包成为一个元组,通过for循环来显示。只要传递的参数传递的参数大于两个,就会自动给默认参数赋值,此时默认参数基本上失去了默认的意义。 

 也可以将默认参数放在*args的后面,但是此时给默认参数赋值时,需要加上关键字,不然就会被打包为元组,赋值给args。

def s(x,*args,y=233):
    print('x =',x)
    print('y =',y)
    for index,i in enumerate(args):
        print('args[%s] = %s'%(index,i))

s(1,2,3,4,5)
输出:
x = 1
y = 233
args[0] = 2
args[1] = 3
args[2] = 4
args[3] = 5

s(1,2,3,4,y=5) 输出: x = 1 y = 5 args[0] = 2 args[1] = 3 args[2] = 4

列表或元组可以以作为参数传入*args,如果不想被二次打包,需要在列表或者元组前面加 * 。

def s(x,*args,y=233):
    print('x =',x)
    print('y =',y)
    for index,i in enumerate(args):
        print('args[%s] = %s'%(index,i))

s(1,2,*[4,5,6])

输出:
x = 1
y = 233
args[0] = 2
args[1] = 4
args[2] = 5
args[3] = 6

五、可变长的关键字参数

可变长关键字参数用 **变量名  来表示,定义函数时,一般用 **kwargs  来表示。主要用来处理一些不能确定有多少个关键字参数的问题。

函数将多余的带关键字的参数打包成为一个字典,关键字为字典的key,进行处理。**kwargs必须是放在函数形参的最后。

def s(x,*args,y=233,**kwargs):
    print('x =',x)
    print('y =',y)
    for index,i in enumerate(args):
        print('args[%s] = %s'%(index,i))
    for i in kwargs:
        print(i,'   ',kwargs[i])
    print('kwargs type is ',type(kwargs))

s(1,2,a=3,b=4)

输出结果:
x = 1
y = 233
args[0] = 2
a     3
b     4
kwargs type is  <class 'dict'>

同样,字典也可以作为参数传入**kwargs,需要在字典前加 **

可以对比下列代码的执行结果:

def s(x,*args,y=233,**kwargs):
    print('x =',x)
    print('y =',y)
    for index,i in enumerate(args):
        print('args[%s] = %s'%(index,i))
    for i in kwargs:
        print(i,'   ',kwargs[i])

s(1,2,{'a':5})

输出:
x = 1
y = 233
args[0] = 2
args[1] = {'a': 5}   #由于该字典不带关键字,会被当成一个非关键字参数打包入args。
s(1,2,a={'a':5})
输出:
x
= 1
y = 233
args[0]
= 2 a {'a': 5} # 此处,该字典带了关键字,会将该字典连同关键字一起进行打包,变为一个嵌套的字典。

s(
1,2,**{'a':5})
输出:
x
= 1
y
= 233
args[0]
= 2
a
5 #由于字典前加上** ,该字典直接被加入kwargs中
原文地址:https://www.cnblogs.com/ohahastudy/p/8097458.html