Python函数参数学习笔记

Posted fanzhiping

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python函数参数学习笔记相关的知识,希望对你有一定的参考价值。

在学习python函数参数的时候,发现python函数有多种参数形式,感觉有必要记录一下,弄懂它们之间的区别和使用,主要参考了廖雪峰的python基础教程:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431752945034eb82ac80a3e64b9bb4929b16eeed1eb9000

1、位置参数

例如:求xn

def power(x, n):
    s = 1
    while n > 0:
        n = n - 1
        s *= x
    print(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 - 1
        s *= x
    print(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: 7
city: 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 is None:
        lis = []
    lis.append(1)
    print(lis)


func() #[1]
func() #[1]

"为什么要设计strNone这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象"

  1、不可变对象:字符串(string)、(数值型number)、元组(tuple)、集合(set)
  2、可变对象:字典型(dictionary)、列表型(list)

3、可变参数

可变参数:传入的参数个数可变

例:给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……,要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来,这样,函数可以定义如下:

def result(numbers):
    sum = 0
    for n in numbers:
        sum += n * n
    return sum

在调用该方法的时候,需要先组装出一个list或tuple

print(result([1, 2, 3]))  #14
print(result((1, 2, 3, 4)))  #30

如果用可变参数的话,就可以直接传入参数,不需要先对参数进行组装,可变参数用*标识

def result(*numbers):
    sum = 0
    for n in numbers:
        sum += n * n
    return sum


print(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)的形式调用它,无论它的参数是如何定义的

 










以上是关于Python函数参数学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

python学习笔记2---函数

Python学习笔记——函数

「学习笔记」3.12代码学习

python cookbook第三版学习笔记九:函数

Python学习 :函数

Python学习笔记__2.1章 调用函数