函数的参数

一:形参与实参

基本概念:
  形参,形式参数,指的是定义函数时,括号内定义的参数,是某种意义上的变量名。
  实参,实际参数,指的是调用函数时,括号内传入的值,是某种意义上的变量值。
注意点:
  实参和形参的绑定关系只有在函数调用时才会生效,调用结束后解除绑定,释放空间。调用函数,就是把实参赋值给形参的过程。

二:位置参数

  位置即顺序,指的是从左到右的顺序依次定义的参数

2.1:位置形参

位置形参的特性:调用时必须为其传值,而且传入的值必须一个不多,一个不少。

# 定义函数时,按照位置顺序定义的形参 
def foo(x,y,z): 
  print(x,y,z)
foo(1,2) #程序报错 
foo(1,2,3,4)#程序报错 
foo(1,2,3) #程序运行正常

2.2:位置实参

调用函数时,按照位置顺序定义传入的值
位置实参特性:位置实参必须与形参一一对应

3.关键字参数

在调用函数时,以key=value形式定义的实参,称为关键字实参,相当于指名道姓的为形参传值,即便是不按照顺序定义,仍然能为指定形参传值

def foo(x,y,z):
    print(x,y,z)
foo(x=1,y=2,z=3) 
foo(x=1,z=2,y=3)
foo(z=3,x=2,y=1)
#在以关键字参数为位置形参传值时,只要按照key=value的形式,就可以不用按照顺序

4.混合参数

在调用函数时,传入的实参同时有位置实参和关键字实参:

  位置实参必须放到关键字实参的前面。

  必须遵循形参的规则。

  不能为同一个形参重复传值

def foo(x, y, z):
    print(x, y, z)

foo(1, 2, z=3) 
foo(x=1, 2, 3) 
foo(1, 2, y=3)  
foo(1, 2, z=3)
foo(x=1, y=2, z=3)  
foo(1, x=2, y=3, z=4) 

5.默认参数

在定义阶段已经为某个形参赋值,那么该形参就被称为默认参数。可以传值也可以不传值,经常需要变的参数定义成位置形参,变化较小的参数定义成默认参数

1:默认参数已有值,,可以传值也可以不用传值

def resgister(name, age, sex="male"):
    print(name, age, sex)

resgister("egon", 18)
resgister("alex", 73, "female")
resgister("wxx", 45)

2:位置形参必须在默认参数的前面;

def resgister(sex="male", name, age):
    print(name, age, sex)

resgister("alex", 73, "female")  # 程序报错

3:默认参数的值,只在定义阶段赋值一次,也就是说在定义阶段默认参数已经写死了

def resgister(name, age, sex="male"):
    print(name, age, sex)

resgister("alex", 73, "female")  # 程序正常

#由程序输出判断y的值由何而来
m = 10
def foo(x, y=m):
    print(x, y)

m = 100
foo(1)

4:默认参数的值应该设置成不可变类型

  默认参数的值是可变类型

def resgister(name, hobby, l=[]):
    l.append(hobby)
    print(name, hobby, l)


# 错误实例
resgister("egon", "play")  # egon play ['play']
resgister("alex", "read")  # alex read ['play', 'read']
resgister("wxx", "sleep")  # wxx sleep ['play', 'read', 'sleep']

# 正确实例
resgister("egon", "play", [])  # egon play ['play']
resgister("alex", "read", [])  # alex read ['read']
resgister("wxx", "sleep", [])  # wxx sleep ['sleep']

把默认参数的值设置成不可变类型

def resgister(name, hobby, l=None):
    if l is None:
        l = []
    l.append(hobby)
    print(name, hobby, l)


resgister("egon", "play")  # egon play ['play']
resgister("alex", "read")  # alex read ['read']
resgister("wxx", "sleep")  # wxx sleep ['sleep']

对于经常需要变化的值,需要将对应的形参定义错位置形参,对于大多数情况值都一样的情况,需要将对应的形参定义成默认形参。

6.可变长参数

可变长指的是实参的个数不确定,而实参有按位置的位置实参和按关键字的关键字实参两种形式,针对这两种形式的可变长,形参对于有两种解决方案来完整的存放他们分别是*args和**kwargs:

  *args:可变长度的位置形参(* 会将溢出的位置实参全部接收,然后保存成元组形式,赋值给args)

  *kwargs:可变长度的关键字形参(** 会将溢出的关键字参数全部接收,然后保存成字典形式,赋值给kwargs)

*args和*kwargs主要的功能都是有*和**完成,后面的argshe kwargs都只是变量名,是什么并不重要,但是约定俗成,也就如此了。

*args是可变长的位置形参,所以也具有位置形参的一切特性,*后定义的参数必须被传值(默认参数除外),切必须以关键字形式传值。

def foo(x, y, *args, a=1, b, **kwargs):
    print(x, y)
    print(args)
    print(a)
    print(b)
    print(kwargs)

7.在实参中的*和**

形参中的 * 和 ** 把溢出的位置实参和关键字实参分别存成了元组和字典,那么在实参中*和**又是有什么功能呢?

实参加*,就把该实参的值打散成字符串

def foo(x,y,z):
    print(x,y,z)
foo(*[1,2,3])
#foo(*[123]) == foo(1,2,3)

实参加**,就把该实参的值打散成关键字参数

def foo(x,y,z,**kwargs):
    print(x,y,z)
    print(kwargs)
foo(1,2,3,**{"a":4,"b":5})
#foo(1,2,3,**{"a":4,"b":5}) == foo(1,2,3,a=4,b=5)

打散的关键字实参和位置实参重复

def foo(x,y,z,**kwargs): 
  print(x,y,z) 
  print(kwargs) 
foo(1,2,3,**{"x":4,"b":5}) 
#TypeError: foo() got multiple values for argument 'x'

 

posted @ 2018-03-27 15:32  Leslie-x  阅读(181)  评论(0编辑  收藏  举报