a - int

*args --tuple

**kwargs -- dict

*args是非关键字参数,用于元组,**kw是关键字参数,用于字典

可变参数

在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。

我们以数学题为例子,给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……。

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

  1.  
    def calc(numbers):
  2.  
    sum = 0
  3.  
    for n in numbers:
  4.  
    sum = sum + n * n
  5.  
    return sum

但是调用的时候,需要先组装出一个list或tuple:

  1.  
    >>> calc([1, 2, 3])
  2.  
    14
  3.  
    >>> calc((1, 3, 5, 7))
  4.  
    84

如果利用可变参数,调用函数的方式可以简化成这样:

  1.  
    >>> calc(1, 2, 3)
  2.  
    14
  3.  
    >>> calc(1, 3, 5, 7)
  4.  
    84

所以,我们把函数的参数改为可变参数:

  1.  
    def calc(*numbers):
  2.  
    sum = 0
  3.  
    for n in numbers:
  4.  
    sum = sum + n * n
  5.  
    return sum

定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:

  1.  
    >>> calc(1, 2)
  2.  
    5
  3.  
    >>> calc()
  4.  
    0

如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:

  1.  
    >>> nums = [1, 2, 3]
  2.  
    >>> calc(nums[0], nums[1], nums[2])
  3.  
    14

这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:

  1.  
    >>> nums = [1, 2, 3]
  2.  
    >>> calc(*nums)
  3.  
    14

*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。

关键字参数

可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple,而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。请看示例:

  1.  
    def person(name, age, **kw):
  2.  
    print('name:', name, 'age:', age, 'other:', kw)

函数person除了必选参数nameage外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数:

  1.  
    >>> person('Michael', 30)
  2.  
    name: Michael age: 30 other: {}

也可以传入任意个数的关键字参数:

  1.  
    >>> person('Bob', 35, city='Beijing')
  2.  
    name: Bob age: 35 other: {'city': 'Beijing'}
  3.  
    >>> person('Adam', 45, gender='M', job='Engineer')
  4.  
    name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

关键字参数有什么用?它可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。

和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:

  1.  
    >>> extra = {'city': 'Beijing', 'job': 'Engineer'}
  2.  
    >>> person('Jack', 24, city=extra['city'], job=extra['job'])
  3.  
    name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

当然,上面复杂的调用可以用简化的写法:

  1.  
    >>> extra = {'city': 'Beijing', 'job': 'Engineer'}
  2.  
    >>> person('Jack', 24, **extra)
  3.  
    name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。

命名关键字参数

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kw检查。

仍以person()函数为例,我们希望检查是否有city和job参数:

  1.  
    def person(name, age, **kw):
  2.  
    if 'city' in kw:
  3.  
    # 有city参数
  4.  
    pass
  5.  
    if 'job' in kw:
  6.  
    # 有job参数
  7.  
    pass
  8.  
    print('name:', name, 'age:', age, 'other:', kw)

但是调用者仍可以传入不受限制的关键字参数:

>>> person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)

如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收cityjob作为关键字参数。这种方式定义的函数如下:

  1.  
    def person(name, age, *, city, job):
  2.  
    print(name, age, city, job)

和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符,后面的参数被视为命名关键字参数。

调用方式如下:

  1.  
    >>> person('Jack', 24, city='Beijing', job='Engineer')
  2.  
    Jack 24 Beijing Engineer

命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:

  1.  
    >>> person('Jack', 24, 'Beijing', 'Engineer')
  2.  
    Traceback (most recent call last):
  3.  
    File "<stdin>", line 1, in <module>
  4.  
    TypeError: person() takes 2 positional arguments but 4 were given

由于调用时缺少参数名cityjob,Python解释器把这4个参数均视为位置参数,但person()函数仅接受2个位置参数。

命名关键字参数可以有缺省值,从而简化调用:

def person(name, age, *, city='Beijing', job):
print(name, age, city, job)

由于命名关键字参数city具有默认值,调用时,可不传入city参数:

  1.  
    >>> person('Jack', 24, job='Engineer')
  2.  
    Jack 24 Beijing Engineer

使用命名关键字参数时,要特别注意,不是参数,而是特殊分隔符。如果缺少,Python解释器将无法识别位置参数和命名关键字参数:

  1.  
    def person(name, age, city, job):
  2.  
    # 缺少 *,city和job被视为位置参数
  3.  
    pass

参数组合

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用,除了可变参数无法和命名关键字参数混合。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数/命名关键字参数和关键字参数。

比如定义一个函数,包含上述若干种参数:

  1.  
    def f1(a, b, c=0, *args, **kw):
  2.  
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
  3.  
     
  4.  
    def f2(a, b, c=0, *, d, **kw):
  5.  
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。

  1.  
    >>> f1(1, 2)
  2.  
    a = 1 b = 2 c = 0 args = () kw = {}
  3.  
    >>> f1(1, 2, c=3)
  4.  
    a = 1 b = 2 c = 3 args = () kw = {}
  5.  
    >>> f1(1, 2, 3, 'a', 'b')
  6.  
    a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
  7.  
    >>> f1(1, 2, 3, 'a', 'b', x=99)
  8.  
    a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
  9.  
    >>> f2(1, 2, d=99, ext=None)
  10.  
    a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}

最神奇的是通过一个tupledict,你也可以调用上述函数:

  1.  
    >>> args = (1, 2, 3, 4)
  2.  
    >>> kw = {'d': 99, 'x': '#'}
  3.  
    >>> f1(*args, **kw)
  4.  
    a = 1 b = 2 c = 3 args = () kw = {'d': 99, 'x': '#'}
  5.  
    >>> args = (1, 2, 3)
  6.  
    >>> kw = {'d': 88, 'x': '#'}
  7.  
    >>> f2(*args, **kw)
  8.  
    a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}

所以,对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。

小结

Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。

默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!

要注意定义可变参数和关键字参数的语法:

*args是可变参数,args接收的是一个tuple

**kw是关键字参数,kw接收的是一个dict

以及调用函数时如何传入可变参数和关键字参数的语法:

可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过*args传入:func(*(1, 2, 3))

关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{'a': 1, 'b': 2})

使用*args**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。

命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。

定义命名的关键字参数不要忘了写分隔符*,否则定义的将是位置参数。

python可变参数类型 a,*args,**kwargs的更多相关文章

  1. python 可变参数函数定义* args和**kwargs的用法

    python函数可变参数 (Variable Argument) 的方法:使用*args和**kwargs语法.其中,*args是可变的positional arguments列表,**kwargs是 ...

  2. Python可变参数*args和**kwargs

    本文我们将通过示例了解 Python函数的可变参数*args和 **kwargs的用法. 知识预备:Python 函数和 Python 函数参数 在Python编程中,我们定义一个函数来生成执行类似操 ...

  3. python可变参数*args, **kwargs

    python可变参数*args, **kwargs def foo(* args, ** kwargs): print ' args = ',  args print ' kwargs = ',  k ...

  4. Java可变参数 & Python可变参数 & Scala可变参数

    Java 可变参数的特点: (1).只能出现在参数列表的最后: (2)....位于变量类型和变量名之间,前后有无空格都可以: (3).调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体 ...

  5. Python 函数参数类型大全(非常全!!!)

    Python 函数参数类型大全(非常全!!!) 1.在python编写程序里面具有函数文档,它的主要作用是为了让别人可以更好的理解你的函数,所以这是一个好习惯,访问函数文档的方式是: MyFuncti ...

  6. Java_可变参数类型

    Java方法中的可变参数类型,也称为不定参数类型,是一个非常重要的概念 举栗子 public class TestVarArgus { public static void dealArray(int ...

  7. 深度解析Java可变参数类型以及与数组的区别

    注意:可变参数类型是在jdk1.5版本的新特性,数组类型是jdk1.0就有了. 这篇文章主要介绍了Java方法的可变参数类型,通过实例对Java中的可变参数类型进行了较为深入的分析,需要的朋友可以参考 ...

  8. Java在方法中定义可变参数类型

    学习目标: 掌握可变参数的应用 学习内容: 1.定义 在方法中传递数组有一种更简单的方式--方法的可变参数,其本质是一个语法糖,目的是让开发者写代码更简单. 2.语法 [修饰符] 返回值类型 方法名称 ...

  9. (十五)python3 可变长参数(arg,*args,**kwargs)

    可变长参数(*args,**kwargs) 一.最常见的是在定义函数时,预先并不知道, 函数使用者会传递多少个参数给你, 所以在这个场景下使用这两个关键字.其实并不是必须写成*args 和**kwar ...

随机推荐

  1. knn原理及借助电影分类实现knn算法

    KNN最近邻算法原理 KNN英文全称K-nearst neighbor,中文名称为K近邻算法,它是由Cover和Hart在1968年提出来的 KNN算法原理: 1. 计算已知类别数据集中的点与当前点之 ...

  2. Meet in the middle算法总结 (附模板及SPOJ ABCDEF、BZOJ4800、POJ 1186、BZOJ 2679 题解)

    目录 Meet in the Middle 总结 1.算法模型 1.1 Meet in the Middle算法的适用范围 1.2Meet in the Middle的基本思想 1.3Meet in ...

  3. 【经典转载】关于Struts2的拦截器

    拦截器(interceptor)是Struts2最强大的特性之一,也可以说是struts2的核心,拦截器可以让你在Action和result被执行之前或之后进行一些处理.同时,拦截器也可以让你将通用的 ...

  4. SqlServer 查看表注释

    SELECT DISTINCT d.name, f.value FROM syscolumns a LEFT JOIN systypes b ON a.xusertype= b.xusertype I ...

  5. XML处理指令

    “处理指令(PIs)允许文档包含用于应用程序的指令.指令并不是文档字符数据的一部分,但是必须通过应用程序传递”. 处理指令可以用于将信息传递给应用程序.处理指令可以出现在文档任意位置的标记外部.可以出 ...

  6. 20180105-Python中dict的使用方法

    字典是Python中常用的内置数据类型之一. 字典是无序的对象集合,只能通过key-value的方式存取数据,字典是一种映射类型,其次key的必须是可hash的不可变类型.字典中的key必须唯一. 1 ...

  7. Introduction to Sound Programming with ALSA

    ALSA stands for the Advanced Linux Sound Architecture. It consists of a set of kernel drivers, an ap ...

  8. Kintex7 XC7K325T 板卡三剑客

    (226)基于Xilinx Kintex-7 FPGA K7 XC7K325T PCIeX8 四路光纤卡   (227)基于Xilinx Kintex-7 FPGA K7 XC7K325T的FMC U ...

  9. cookie和session的联系与区别

    Cookie 当你在浏览网站时,WEB服务器会先送一小小的资料放在你的计算机上,Cookie会帮你在网站上所打的文字或是一些选择都记录下来.当你下次再光临同一个网站时,WEB服务器会先看看有没有它上次 ...

  10. Hibernate与 MyBatis的区别

    第一章     Hibernate与MyBatis Hibernate 是当前最流行的O/R mapping框架,它出身于sf.net,现在已经成为Jboss的一部分. Mybatis 是另外一种优秀 ...