Python函数的参数多达5种,不像Java那样参数只有一种,而是像C++那样提供默认参数,除此之外,还提供可变参数、关键字参数、命名关键字参数,这样就使得Python函数的参数变得十分复杂。但复杂意味着灵活便捷,Python语言之所以流行起来,与起本身巨大的灵活性是分不开的。可以说Python是最方便使用的语言。
Python参数类型:
- 位置参数(positional arguments,官方定义,就是其他语言所说的参数)
- 默认参数(类似C++的默认参数)
- 可变参数
- 命名关键字参数
- 关键字参数
位置参数
位置(参数positional arguments)就是其他语言的参数,其他语言没有分参数的种类是因为只有这一种参数,所有参数都遵循按位置一一对应的原则。
import math
def quadratic(a, b, c):
delta = b*b - 4*a*c
if delta < 0:
raise TypeError('operand not appropriate(delta < 0)')
k1 = (-b + math.sqrt(delta)) / (2*a)
k2 = (-b - math.sqrt(delta)) / (2*a)
return k1,k2
print(quadratic(1, 2, 1)) #a、b、c 与 1、2、1一一对应 结果(-1, -1)
#从本例可以看出python函数可以有"多个"返回值,其实是一个tuple
默认参数
Python的默认参数完全等同于C++,引入默认参数是为了在某些情境下提供方便。
形式: 参数名 = 默认值
def personinfo(name, age, gender = 'Female'):
print(name, age, gender)
person('Steve', 22, 'male')
person('Lily', 23) #有了默认参数之后,gender这个参数可以不提供 也可以调用函数 gender被赋了默认值Female
意义何在?
如果使用该函数在一个男女比例均等的学校显示学生信息,则无差别。但如果我在日本女子高中显示学生信息,优势就很明显了,我不需要在每次调用这个函数时输入第三个参数”Female”
默认参数需要注意的地方
默认参数必须在最右端,这样才能被解释器正确识别,否则会产生二义性。
def fun(a=10, b):
return a + b
>>> fun(20)
#二义性:这个20究竟是赋值给a的还是b的
#人都无法分辨清楚,解释器就更不行了
另外:
def defaultzero(list = []): #我们的本意是提供的list参数为0时 返回只有一个0的list
list.append(0)
return list
>>> defaultzero()
[0]
>>> defaultzero()
[0, 0]
#显然重复调用的时候结果不是我们所期望的
#解决方案 使用None
def defaultzero(list = None):
if list = None: list = []
list.append(0)
return list
#这说明list是一个对象
#事实上Python所有的数据类型其实都是对象(先记住这点,后面的博文将给出详细解释)
结果说明python解释器会将默认参数作为一个公共对象来对待,多次调用含有默认参数的函数,就会进行多次修改。
因此定义默认参数时一定要使用不可变对象(int、float、str、tuple)。使用可变对象语法上没错,但在逻辑上是不安全的,代码量非常大时,容易产生很难查找的bug。
可变参数
Python函数提供了可变参数,来方便进行参数个数未知时的调用。可变参数将以tuple形式传递。
格式: *参数
(即在参数前加*号)
def getsum(*num):
sum = 0
for n in num:
sum += n
return sum
list = [2, 3, 4]
print(getsum(1, 2, 3))
print(getsum(*list))
#结果:6 9
请注意: *在C语言中是取内容运算符,变量前加该符号意为指针变量,Python中只是一个标识符,表示将以tuple形式传递,星号本身有”全部的”意思, 两者无任何关系,下同。
关键字参数
Python的可变参数以tuple形式传递,而关键字参数则是以dict形式传递。
即可变参数传递的是参数值,关键字参数传递的是参数名:参数值键值对。
形式:**kw
这是惯用写法,建议使用,容易被理解
def personinfo(name, age, **kw):
print('name:', name, 'age:', age, 'ps:', kw)
>>> personinfo('Steve', 22)
>>> personinfo('Lily', 23, city = 'Shanghai')
>>> personinfo('Leo', 23, gender = 'male',city = 'Shanghai')
可变参数和关键字参数都可以接受0个或者多个参数
命名关键字参数
Python的命名关键字参数对传入的关键字参数做了进一步的限制。
格式:在关键字参数前增加一个”*”。
def personinfo(name, age, *, gender, city): #只能传递gender和city参数
print(name, age, gender, city)
>>> personinfo('Steve', 22, gender = 'male', city = 'shanghai')
Steve 22 male shanghai
关键字参数和命名关键字参数的区别在于,前者可以传递任何名字的参数,而后者只能传递*后面名字的参数。
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
def personinfo(name, age, *args, gender, city): #args可以传递一个list 其后只能传递gedner和city参数
print(name, age, gender, city)
>>> personinfo('Steve', 22, gender = 'male', city = 'shanghai')
Steve 22 male shanghai
各种参数之间组合
一次函数调用可以传递以上所述任何一种参数或者多种参数的组合,当然也可以没有任何参数。正如默认参数必须在最右端一样,使用多种参数时也对顺序有严格要求,也是为了解释器可以正确识别到每一个参数。
顺序:基本参数、默认参数、可变参数、命名关键字参数和关键字参数。
def function(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
对于任意函数包含可变参数和关键字参数的函数,都可以通过类似function(*args, **kw)
的形式调用它,无论它的参数是如何定义的,想想看为什么?。
可读性是代码的一个很重要的要求,所以尽量避免使用多种参数的组合。
补充内容:
Python 函数中,参数是传值,还是传引用?