目录
1. 函数调用
1.1 常用函数的调用
调用绝对值 abs() 函数:
>>> abs(-100)
100
也可以把函数名赋给一个变量,相当于给这个函数起一个“别名”:
>>> a=abs
>>> a(-1)
1
调用 max() 函数:可接收任意多个参数,并返回最大值。
>>> max(2,13,0,-6)
13
2. 定义函数
2.1 函数的定义
定义一个函数要使用 def 语句,依次写出 函数名、括号、括号中的参数和冒号:,用 return 返回。
>>> def my_abs(x):
... if x>=0: # 注意缩进问题
... return x
... else:
... return -x # 按两次回车键重新回到python解释器
...
>>> print(my_abs(-1))
1
在Python交互环境中定义函数时,会出现 ... 的提示。函数定义结束后按两次回车即可重新回到 >>> 提示符下。
2.2 空函数
如果想定义一个什么也不做的空函数,可用 pass 语句:
def nop():
pass
如果现在还没想好怎么写函数的代码,就可以先放一个 pass,让代码能运行起来。
2.3 返回多个值
>>> import math # 导入math包
>>>
>>> def move(x, y, step, angle=0):
... nx = x + step * math.cos(angle)
... ny = y - step * math.sin(angle)
... return nx, ny
...
>>> x,y=move(10,10,6,math.pi/3)
>>> print(x,y)
13.0 4.803847577293368
函数可以同时返回多个值,但其实就是一个 tuple (在语法上,返回一个 tuple 可以省略括号)。
>>> r=move(10,10,6,math.pi/3)
>>> print(r)
(13.0, 4.803847577293368)
3. 函数的参数
3.1 位置参数
def power(x): # 参数x就是一个位置参数
return x*x
3.2 默认参数
def power(x,n=2): # n为默认参数
...
!!!定义默认参数易出错问题:
>>> def add_end(L=[]):
... L.append('END')
... return L
...
>>> add_end()
['END']
>>> add_end() # 再次调用时出现了两次END
['END', 'END']
原因:Python 函数在定义的时候,默认参数 L
的值就被计算出来了,即 []
,因为默认参数 L
也是一个变量,它指向对象 []
,每次调用该函数,如果改变了 L
的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的 []
了。
所以,定义默认参数时必须指向不变对象!!!
解决办法:
可以修改成如下模式,这样调用多少次都不会出现问题。
>>> def add_end(L=None):
... if L is None:
... L=[]
... L.append('END')
... return L
...
>>> add_end()
['END']
>>> add_end()
['END']
3.3 可变参数
定义可变参数和定义一个 list 或 tuple 参数相比,仅仅在参数前面加了一个 * 号。在函数内部,参数接收到的是一个 list 或 tuple 。因此调用该函数时可以传入任意个参数,包括0个参数。如定义一个计算平方和的函数:
>>> def calc(*numbers):
... sum=0
... for n in numbers:
... sum=sum+n*n
... return sum
...
>>> calc(1,2)
5
>>> calc()
0
如果已有一个 list 或 tuple ,可在 list 或 tuple 前加一个 * 号,把 list 或 tuple 的元素变成可变参数传进去:
>>> nums=[1,2,3]
>>> calc(*nums)
14
3.4 关键字参数
允许传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个 dict (如关键字参数**kw),如:
>>> def person(name,age,**kw):
... print('name:',name,'age:',age,'other:',kw)
...
>>> person('zhangsan',21,gender='M',job='Engineer')
name: zhangsan age: 21 other: {'gender': 'M', 'job': 'Engineer'}
也可先组装出一个 dict ,然后把 dict 转换为关键字参数传进去:
>>> extra={'city':'Wuhan','job':'Engineer'}
>>> person('Jack',24,**extra)
name: Jack age: 24 other: {'city': 'Wuhan', 'job': 'Engineer'}
kw 获得的 dict 是 extra 的一份拷贝,不会影响到函数外的 extra 。
如果要限制关键字参数的名字,可以用命名关键字参数。用分隔符 * 隔开。
>>> def person(name,age,*,city,job): # 只接收city和job作为关键字参数
... print(name,age,city,job)
...
>>> person('Jack',24,city='Wuhan',job='Engineer')
Jack 24 Wuhan Engineer
!命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错。
区分:*args 是可变参数,args接收的是一个 tuple ;
**kw 是关键字参数,kw 接收的是一个 dict .
3.5 参数组合
参数定义顺序为:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
4. 递归函数
4.1 递归函数的定义
递归函数即在函数内部调用自身本身。如计算阶乘,用函数 fact() 表示:
>>> def fact(n):
... if n==1:
... return 1
... return n*fact(n-1)
...
>>> fact(3)
6
>>> fact(5)
120
以 fact(5) 为例,函数计算过程如下:
===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120
4.2 尾递归
使用递归函数时要注意栈溢出情况(递归函数调用次数过多,会导致栈溢出)。
解决栈溢出方法:通过尾递归优化,即在函数返回的时候,调用自身本身,并且 return 语句不能包含表达式。
尾递归函数示例:
>>> def fact(n):
... return fact_iter(n,1)
...
>>> def fact_iter(num,product):
... if num==1:
... return product
... return fact_iter(num-1,num*product)
...
>>> fact(5)
120
>>> fact(1)
1
然而要注意的是:Python标准解释器并没有针对尾递归做优化,任何递归函数都存在栈溢出的情况。
好啦!函数基础学习就到这里了,我们下期见!