Python-2 函数、参数
函数
-
help(abs)
:查看函数abs
的帮助信息。 -
pass
:占位符,还没想好怎么写,先pass
,让程序跑起来看一下。- 比如在 if 语句下,定义函数如下。
def my_abs(x): if not isinstance(x, (int, float)): raise TypeError('bad operand type') if x >= 0: return x else: return -x
-
定义函数下,第一行使用:
"函数的说明注释"
。 -
Python 可以返回多个值,
return x, y
。 -
接收:
x, y = testFunc(xxx)
。
- 返回的其实是一个元组,多个变量接收一个元组,则元组将元素按顺序赋值给变量。
isinstance(x, (int, float))
:x
是否为 int 或 float 类型。
raise TypeError('错误提示文本')
:抛出指定提示语的类型错误。
默认参数
不同于 java ,Python 可以有默认参数,可写成 def power(x, n=2)
,此时调用 power(5)
,相当于 power(5, 2)
默认参数为可变类型的误区
有一函数 def add_end(L[])
:多次调用 add_end()
(不传参数,使用默认参数),则会发现这个默认参数被存下来了。
def add_end(L=[]):
L.append('END')
return L
>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']
def
中,默认参数被定义了,只计算一次,拥有了一个内存地址。直接调用默认参数的话(没给参数),会对该地址进行操作。如果是列表、字典或类实例等可变对象时,将会导致该默认参数发生改变。
所以应该尽量使默认参数为不可变参数。
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
- 这里,
def
中的参数是固定不变的。在函数里每次都新建了一个列表,多次调用函数使用默认参数,都会独自生成。
位置参数
函数的不加任何东西的参数默认是位置参数(必需参数),不可缺少。
函数内可以再定义函数,并且这个内部函数可以访问外部函数的参数和局部变量。
-
位置参数在定义里必须是在开头位置的。
-
(此点学习关键字参数后可懂)多种类型参数调用函数时,位置参数必须要也在开头对应位置。除非也将位置参数,使用其关键字传入。
比如函数
def test(a, b=100, c=100)
:test(b=2, 1)
是错误的。而test(b=2, a=1)
是可以的。一般的常用方式是
test(1, 2)
,即位置参数一般不用关键字。而关键字参数在有多个关键字可选、要区分的话,常使用关键字传入:test(1,b=2, c=3)
。
可变参数
定义可变参数的函数(java 里的 ...
):
def calc(*numbers)
- 可变参数
numbers
在函数里被合并为一个元组numbers
,在外面调用函数直接传进来多个值即可。 - 调用函数时,也可以使用:
calc(*tuple1)
,直接将一个元组/列表作为参数(类似于解构)。
def computed(x, y, *z):
print("可变参数:", z)
print("两个位置参数:", x, y)
x = [1, 1, 2, 2]
computed(*x)
可变参数: (2, 2)
两个位置参数: 1 1
关键字参数
关键字参数 **kw
相当于可变参数 *args
的变种,也是一种可选的,但是它是键值对形式。
主要是可以让我们在使用函数的时候,不需要顾及参数的位置,直接将对应关键字传入即可。
注意到关键字参数与默认参数实际上是一样的。
def person(name, age, **kw):
kw
是 字典,键值对;name
,age
为位置参数。name
,age
位置参数是必要的,而关键字参数是次要的,扩展的。- 调用:
person('Bob', 18, city='Xiamen', job='ceo')
,必须传入参数名,否则会被识别为位置参数,出现错误。 - 同样,调用函数时使用
person('Bob', 18, **extra)
,将一个名为extra
的字典做为参数传入。
- 值得注意的是,这里的
**extra
只是extra
的一个浅拷贝,函数内的对不可变元素的操作不会影响外部的extra
,但操作可变元素有影响。
- 位置参数可以使用关键字参数传入。此时不需要考虑他们的顺序问题。
命名关键字参数/仅限关键字参数:限制关键字参数的名字
def person(name, age, *, city='Beijing', job): # 在星号后面写上关键字参数应有的键名
这里除必须参数外,还限制必须【要有且仅有】名为 city
,job
的参数传进来。
- 如果有可变参数,可变参数后面的关键字参数可以不再用
*
分隔了,后面默认是命名关键字参数:def person(name, age, *args, city, job)
。 - 如果关键字参数有默认值,则可以不用必须传入
- 比如这样可以调用上面小标题下的函数:
person('Jack', 24, job='Engineer')
- 比如这样可以调用上面小标题下的函数:
强制位置参数/仅限位置参数
在上面的参数中的,调用时:
- 如
f(10)
使用的是位置参数,没有,是没有带名字的参数 f(a=10)
使用的是关键字参数/命名关键字参数,带有名字
Python 3.8 新增了一种参数 /
,使得前面的参数调用必须使用位置参数:
def f(a, b, /, c, d, *, e, f)
print(a, b, c, d, e, f)
以下使用方法是正确的:
f(10, 20, 30, d=40, e=50, f=60)
以下使用方法会发生错误:
f(10, b=20, c=30, d=40, e=50, f=60) # b不能使用关键字参数的形式
f(10, 20, 30, 40, 50, f=60) # e必须使用关键字参数的形式
仅限位置参数应放在
/
(正斜杠)前。/
用于在逻辑上分割仅限位置形参与其它形参。仅限关键字参数放在
*
之后。
参数组合
有多种参数的话,按照逻辑以及要求,必须按顺序来:必选参数(位置参数)、默认参数、可变参数、命名关键字参数和关键字参数。
def f(a, b, c=0, *, d, **kw):
# 必 必 默 命名 关键
# f函数要有a,b,可选c参数,还必须要有d=value
# 因为有**kw,所以还可有其他带名字的键值对传入
# 这里没有演示可变参数:def f(a, b, c=0, *args, d, **kw)
对于任意函数,都可以通过类似 func(*args, **kw)
的形式调用它,无论它的参数是如何定义的。
*args
包括必选参数、可变参数。**kw
包括默认参数、关键字参数、命名关键字参数。
递归函数
解决递归调用栈溢出的方法:尾递归
大多数编程语言没有针对尾递归做优化,Python 解释器也没有做优化,所以,即使把阶乘的 fact(n)
自定义函数改成尾递归方式,也会导致栈溢出。
匿名函数
lambda 表达式,它是一个表达式,只包含一个语句,而不是一个代码块。仅能在 lambda 表达式中封装有限的逻辑进去。
lambda [arg1[, arg2,.....argn]]:expression
# 冒号前参数,冒号后表达式
示例:
sum = lambda arg1, arg2: arg1 + arg2
# 调用sum函数
print("相加后的值为: ", sum(10, 20))
print("相加后的值为: ", sum(20, 20))