1、位置参数
例如:求xn
defpower(x, n):
s= 1
while n >0:
n= n - 1s*=xprint(s)
power(3, 4) #81
power(4, 3) #64
可见,调用函数时,传入的值按照顺序依次赋给了x、n
在调用函数的时候,有多少个位置参数,就必须传入多少个值,否则会报错
power(3)
TypeError: power() missing 1 required positional argument: 'n'
提示power()函数缺少1个需要的位置参数'n',从这儿也可以看出,位置参数是依次传值的
2、默认参数
默认参数:在函数定义的时候,直接指定参数的值
def power(x, n=2):
s= 1
while n >0:
n= n - 1s*=xprint(s)
在本例中,power()函数给定了默认参数n=2,这种情况下,如果我们仅仅需要调用power()函数求一个数x的平方,在调用该函数时,就可以只传入x的值
power(3) # 9
如果我们想调用power()函数求x的4、5、6...次方的话,就可以通过给默认参数传入值的方式
power(3, 4) # 81
可见,默认参数能够简化函数的调用,这在一个函数的某些参数在多数情况下不需要改变时非常有用。比如:打印一个班级学生的姓名(name),年龄(age)和籍贯(city)信息
通常来讲,一个班级的同学的籍贯都是同一地区的,如果每次调用都要传入city参数,会使调用变得复杂,这个时候,可以将city参数设置成默认参数
def student(name, age, city='chongqing'):print('name:', name)print('age:', age)print('city:', city)
student('fzp', 7)
输入结果:
name: fzp
age:7city: chongqing
设置默认参数时,需要注意一下几点:
1)必选参数必须在前,默认参数在后
2)当函数有多个参数时,把变化大的放在前面,变化小的参数放后面。变化小的参数就可以作为默认参数
好处:降低调用函数的难度
3)当有多个默认参数时,可以按顺序赋值,也可使用参数名直接赋值
对于第3点:
def student(name, age, city='chongqing', gender=7):print('name:', name)print('age:', age)print('city:', city)print('gender:', gender)
student('frm', 7, 'chengdu', 6) #依顺序赋值
student('fzp', 7, gender=7) #给gender参数赋值为7,这种情况下,city参数仍是默认的‘chongqing’
默认参数的一个典型问题,使用的时候需要注意:
def func(lis=[]):
lis.append(1)print(lis)
func() #[1]
func() #[1, 1]
"这是因为解释器执行函数定义时,默认参数值lis也被计算了,即[],因为默认参数lis也是一个变量,它指向对象[],每次调用该函数,如果改变了lis的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了"引用廖大的解释
对于该问题,我的理解是在执行append()方法时,只是往lis里面添加了新的元素,并未改变其地址
lis =[]print(id(lis)) #2293538950856
lis.append(1)print(id(lis)) #2293538950856
解决该问题,可以用None这个不变对象来实现:
def func(lis=None):if lis isNone:
lis=[]
lis.append(1)print(lis)
func() #[1]
func()#[1]
"为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象"
1、不可变对象:字符串(string)、(数值型number)、元组(tuple)、集合(set)
2、可变对象:字典型(dictionary)、列表型(list)
3、可变参数
可变参数:传入的参数个数可变
例:给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……,要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来,这样,函数可以定义如下:
defresult(numbers):
sum=0for n innumbers:
sum+= n *nreturn sum
在调用该方法的时候,需要先组装出一个list或tuple
print(result([1, 2, 3])) #14print(result((1, 2, 3, 4))) #30
如果用可变参数的话,就可以直接传入参数,不需要先对参数进行组装,可变参数用*标识
def result(*numbers):
sum=0for n innumbers:
sum+= n *nreturnsumprint(result(1, 2, 3, 4)) #30 直接给result函数传值
tup= (1, 2, 3)print(result(*tup)) #14 也可以传入一个list或tuple,但需要在其前面加上*符号,否则会报错:TypeError: can't multiply sequence by non-int of type 'tuple'
4、关键字参数
关键字参数:允许传入任意个(包括0个)含参数名的的参数,这些参数在函数内部会自动组装成一个dict,关键字参数用**标识
def student(name, age, **kwargs):print('name:', name, 'age:', age, 'other:', kwargs)
可见,student函数除了必选参数name和age外,还可接受关键字参数kwargs,在调用该函数的时候,可以只传入必选参数
student('fzp', 24)
输出结果为:
name: fzp age: 24 other: {}
从结果也可以看出,关键字参数在函数内部自动组装成了一个dict,此处,关键字参数未传值,所有是一个空字典{}
关键之参数传值可采用 'key' = 'value' 的形式
student('fzp', 24, address='chongqing', sex='man')
输出结果为:
name: fzp age: 24 other: {'address': 'chongqing', 'sex': 'man'}
当然,关键字参数传值可以直接传入一个dict
dic = {'address': 'chongqing', 'sex': 'man'}
student('fzp', 24, **dic)
输出结果为:
name: fzp age: 24 other: {'address': 'chongqing', 'sex': 'man'}
注意:
1、kwargs获得的dict仅仅是dic的一个拷贝,对kwargs的改变不会影响函数外面的dic
2、直接传入一个dict时,要在之前添加**,否则会将整个dict识别为一个位置参数,如下:
student('fzp', 24, dic)
TypeError: student() takes 2 positional arguments but 3 were given
命名关键字参数
对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。但是,又是我们或许想要限定关键字参数的名字,这时,就需要用到命名关键字参数
仍以student函数为例,如果只想接受address和sex为参数,可定义如下:
def student(name, age, *, address, sex):print('name:', name, 'age:', age, 'address:', address, 'sex:', sex)
和关键字参数**kwargs不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数
调用方式如下:
student('fzp', 23, address='chongqing', sex='man')
输入结果:name: fzp age: 23 address: chongqing sex: man
注意:命名关键字参数必须给值,至于为什么有了必传的位置参数,还要有必传的命名关键字参数,我觉得主要有两点原因:
1、命名关键字参数通过指定参数名称的方式,可以明确当前参数的含义
2、命名关键字参数不必像位置参数那样按顺序传值,时传值更加灵活
当然,命名关键字参数可以有缺省值,这样,在调用的时候,就不必给其传入值了:
def student(name, age, *, address, sex='man'):print('name:', name, 'age:', age, 'address:', address, 'sex:', sex)
调用该函数:
student('fzp', 23, address='chongqing')
输出结果为:name: fzp age: 23 address: chongqing sex: man
5、参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数
举例:
def func(a, b, c=3, *args, address, **kwargs):print('a:', a, 'b:', b, 'c:', c, 'args:', args, 'address:', address, 'kwargs:', kwargs)
调用该函数:
func(1, 2, 3, 4, 5, address='cq', d='char', e='dict')
输入结果为:a: 1 b: 2 c: 3 args: (4, 5) address: cq kwargs: {'d': 'char', 'e': 'dict'}
通过一个tuple和dict,也可以调用上述函数:
tup = (1, 2, 3, 4, 5)
kw= {'address': 'cq', 'ax': 'sg'}
func(*tup, **kw)
输出结果为:
a: 1 b: 2 c: 3 args: (4, 5) address: cq kwargs: {'ax': 'sg'}
所以,对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的