据廖雪峰python3教程----python学习第八天

简介:

函数的参数


定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。

python的函数除了正常的定义必选参数外,还可以使用默认参数,可变参数合关键字参数,


位置参数


定义一个计算x 的平方的函数

1
2
3
4
5
6
>>>  def  power(x):                #参数 x 就是一个位置参数
      return  x * * 2
>>> power( 5 )
25
>>> power( 15 )
225


为了方便我们再定义一个可以计算 x 的任意次的函数

1
2
3
4
5
6
>>>  def  powern(x,n):
      return  x * * n
>>> powern( 5 , 2 )
25
>>> powern( 2 , 3 )
8


这是powern中的 x,n  都是位置参数,按 x和n 的位置对应的传入参数




默认参数


对于powern(x,n)如果只穿入一个参数

1
2
3
4
5
>>> powern( 5 )
Traceback (most recent call last):
   File  "<pyshell#10>" , line  1 in  <module>
       powern( 5 )
TypeError: powern() missing  1  required positional argument:  'n'

python会抛出错误提示少一个参数


这时我们可以 设置 默认参数:

1
2
3
4
5
6
>>>  def  powern(x,n = 2 ):           #在这里把n=2 设置位默认参数
      return  x * * n
      
>>> powern( 5 )
25 >>> powern( 5 , 3 )
125


当只输入一个参数x 时相当于 计算 x 的平方



设置默认函数可以简化函数的调用。设置默认参数时,有有几点需要注意:

1:必选参数在前,默认参数在后。

2:如何设置默认参数。当函数有多个参数时,把变化大的参数放在前面,变化小的参数放在后面。变化小的参数就可以设置为默认参数。



默认参数很有用,但使用不当会掉坑,默认参数有个最大的坑,比如:

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

1
2
3
>>>  def  add_end(L = []):
      L.append( 'END' )
      return  L


调用时,结果似乎不错:

1
2
3
4
>>> add_end([ 1 , 2 , 3 ])
[ 1 2 3 'END' ]
>>> add_end([ 'x' , 'y' , 'z' ])
[ 'x' 'y' 'z' 'END' ]


使用默认参数是,一开始结果也不错:

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


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

1
2
3
4
>>> add_end()
[ 'END' 'END' ]
>>> add_end()
[ 'END' 'END' 'END' ]


函数似乎“记住了”上次添加了‘end’的list


为什么呢:

python在定义的时候,默认参数L的值就被计算出来,即[ ] ,因为默认参数L也是一个变量,它指向对象 

[ ]  ,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不在是定义的 [ ] 了。


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


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

1
2
3
4
5
>>>  def  add_end(L = None ):
      if  is  None :
         L =  []
      L.append( 'END' )
      return  L


这用我们在调用就不会出错了:

1
2
3
4
>>> add_end()
[ 'END' ]
>>> add_end()
[ 'END' ]

在做一下对比:

1
2
3
4
5
6
7
8
9
10
>>>  def  add_end(L = []):
     if  is  None :
         L = []
     L.append( 'END' )
     return  L    
     
>>> add_end()
[ 'END' ]
>>> add_end()             
[ 'END' 'END' ]

可变参数


可变参数就是传入参数的个数是可变的,可以是任意个。

比如:给定一组数字a,b,c........,计算 a2 + b2+ c2 + ……。

要定义出这个函数,我们必须确定输入的参数。由于参数个数是不确定的,我们首先想到可以吧a,b,c,.......。作为一个list或tuple 传进去,这样函数可定义为:

1
2
3
4
5
>>>  def  calc(number):
      sum = 0
      for  in  number:
        sum = sum + n * * 2
      return  sum

但是在调用的时候,需要先组装出一个list或tuple:

1
2
3
4
>>> calc([ 1 , 2 , 3 ])
14
>>> calc([ 1 , 2 , 3 , 4 ])
30

如果利用可变参数,调用函数的方式可以简化:

1
2
3
4
>>> calc( 1 , 2 , 3 )
14
>>> calc( 0 )
0

所以我们需要把函数改变为可变参数:

1
2
3
4
5
>>>  def  calc( * number):
      sum = 0     
      for  in  number:   
        sum = sum + n * * 2
      return  sum


定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数的内部,参数 number 接受到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数。

1
2
>>> calc()
0

如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:

1
2
3
>>> nums = [ 1 , 2 , 3 ]
>>> calc(nums[ 0 ],nums[ 1 ],nums[ 2 ])
14

这种方法太繁琐,所以 python 允许在list或tuple的元素前面加一个*号,把list或tuple的元素变成可变参数传进去:

1
2
>>> calc( * nums)
14


*num表示把num这个list的所有元素作为可变参数穿进去。这种写法相当有用,而且很常见。



关键字参数


可变参数允许你传入0或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个参数或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

1
2
>>>  def  person(name,age, * * kw):
      print ( 'name:' ,name, 'age:' ,age, 'other:' ,kw)

函数person除了必选参数 name 和 age 外,还接受关键字参数 kw 。在调用该函数是,可以之传入必选参数:

1
2
3
4
5
6
>>> person( 'Michael' , 30 )
name: Michael age:  30  other: {}
>>> person( 'Bob' , 35 ,city = 'BeiJing' )
name: Bob age:  35  other: { 'city' 'BeiJing' }
>>> person( 'xiaoming' , 19 ,gender = 'M' ,job = 'Enginerr' )
name: xiaoming age:  19  other: { 'gender' 'M' 'job' 'Enginerr' }


关键字参数有什么用?它可以扩展函数的功能。比如,在person函数里,我们保证能接收到nameage这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。


和可变关键字类似,也可以先组装出一个dict,然后,吧该dict转换为关键字参数传进去:

1
2
3
>>> exter = { 'city' : 'BeiJing' , 'Job' : 'Engineer' }
>>> person( 'Jack' , 24 ,city = exter[ 'city' ],job = exter[ 'Job' ])
name: Jack age:  24  other: { 'job' 'Engineer' 'city' 'BeiJing' }


当然,上面复杂的调用可以用简化的写法:

1
2
>>> person( 'Jack' , 24 , * * exter)
name: Jack age:  24  other: { 'Job' 'Engineer' 'city' 'BeiJing' }


**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra



命名字关键字参数


对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部用过 kw 检查

1
2
3
4
5
6
>>>  def  person(name,age, * * kw):
      if  'city'  in  kw:           #city有参数
        pass  
       if  'job'  in  kw:           #有job参数  
          pass
      print ( 'name:' ,name, 'age' ,age, 'other:' ,kw)

但是任可以传入不受限制的关键字参数:

1
2
>>> person( 'jack' , 24 ,city = 'beijing' ,addr = 'chaoyang' ,zipcode = 123456 )
name: jack age  24  other: { 'zipcode' 123456 'addr' 'chaoyang' 'city' 'beijing' }


如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收cityjob作为关键字参数。这种方式定义的函数如下:

1
2
>>>  def  person(name,age, * ,city,job):
      print (name,age,city,job)


和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。

1
2
>>> person( 'jack' , 24 ,city = 'beijing' ,job = 'engineer' )
jack  24  beijing engineer


命名关键字参数传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:

1
2
3
4
5
>>> person( 'jack' , 24 , 'beijing' , 'engineer' )
Traceback (most recent call last):
   File  "<pyshell#85>" , line  1 in  <module>
       person( 'jack' , 24 , 'beijing' , 'engineer' )
TypeError: person() takes  2  positional arguments but  4  were given

由于调用时缺少参数名cityjob,Python解释器把这4个参数均视为位置参数,但person()函数仅接受2个位置参数。



命名关键字参数可以有缺省值,从而简化调用:

1
2
>>>  def  person(name,age, * ,city = 'BeiJing' ,job):
      print (name,age,city,job)


由于命名关键字参数city具有默认值,调用时,可不传入city参数:

1
2
>>> person( 'Jack' , 24 ,job = 'Engineer' )
Jack  24  BeiJing Engineer


使用命名关键字参数时,要特别注意,*不是参数,而是特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数:

1
2
3
>>>  def  person(name,age,city,job):
      #缺少 *, city 和job 被视为位置参数
      pass

参数组合


在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用,除了可变参数无法和命名关键字参数混合。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数/命名关键字参数和关键字参数。


比如定义一个函数,包含上述若干种参数:

1
2
3
4
5
6
def  f1(a, b, c = 0 * args,  * * kw):
     print ( 'a =' , a,  'b =' , b,  'c =' , c,  'args =' , args,  'kw =' , kw)
     
     
def  f2(a, b, c = 0 * , d,  * * kw):
     print ( 'a =' , a,  'b =' , b,  'c =' , c,  'd =' , d,  'kw =' , kw)



在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。

1
2
3
4
5
6
7
8
9
10
>>> f1( 1 2 )
=  1  =  2  =  0  args  =  () kw  =  {}
>>> f1( 1 2 , c = 3 )
=  1  =  2  =  3  args  =  () kw  =  {}
>>> f1( 1 2 3 'a' 'b' )
=  1  =  2  =  3  args  =  ( 'a' 'b' ) kw  =  {}
>>> f1( 1 2 3 'a' 'b' , x = 99 )
=  1  =  2  =  3  args  =  ( 'a' 'b' ) kw  =  { 'x' 99 }
>>> f2( 1 2 , d = 99 , ext = None )
=  1  =  2  =  0  =  99  kw  =  { 'ext' None }



最神奇的是通过一个tuple和dict,你也可以调用上述函数:

1
2
3
4
5
6
7
8
>>> args  =  ( 1 2 3 4 )
>>> kw  =  { 'd' 99 'x' '#' }
>>> f1( * args,  * * kw)
=  1  =  2  =  3  args  =  ( 4 ,) kw  =  { 'd' 99 'x' '#' }
>>> args  =  ( 1 2 3 )
>>> kw  =  { 'd' 88 'x' '#' }
>>> f2( * args,  * * kw)
=  1  =  2  =  3  =  88  kw  =  { 'x' '#' }


所以,对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。




本文转自 nw01f 51CTO博客,原文链接:http://blog.51cto.com/dearch/1760470,如需转载请自行联系原作者

相关文章
|
3天前
|
机器学习/深度学习 算法 Python
使用Python实现集成学习算法:Bagging与Boosting
使用Python实现集成学习算法:Bagging与Boosting
15 0
|
3天前
|
Python
python学习-函数模块,数据结构,字符串和列表(下)
python学习-函数模块,数据结构,字符串和列表
25 0
|
5天前
|
Python
python学习14-模块与包
python学习14-模块与包
|
5天前
|
Python
python学习12-类对象和实例对象
python学习12-类对象和实例对象
|
5天前
|
数据采集 Python
python学习9-字符串
python学习9-字符串
|
5天前
|
Python
python学习10-函数
python学习10-函数
|
5天前
|
存储 索引 Python
python学习7-元组
python学习7-元组
|
5天前
|
Python
python学习8-集合
python学习8-集合
|
5天前
|
Python
python学习4-内置函数range()、循环结构、循环控制语句、else语句、嵌套循环
python学习4-内置函数range()、循环结构、循环控制语句、else语句、嵌套循环
|
5天前
|
存储 索引 Python
python学习5-列表的创建、增删改查、排序
python学习5-列表的创建、增删改查、排序