Python函数参数操作详解


Posted in Python onAugust 03, 2018

本文实例讲述了Python函数参数操作。分享给大家供大家参考,具体如下:

简述

在 Python 中,函数的定义非常简单,满足对应的语法格式要求即可。对于调用者来说,只需关注如何传递正确的参数,以及获取相应的返回值就足够了,无需了解函数的内部实现(除非想学习、跟踪源码)。

话虽如此,但对于函数的定义来说,灵活性非常高。除了常规定义的必选参数以外,还支持默认参数、可变参数、以及关键字参数。这样以来,不但能处理复杂的参数,还可以简化调用者的代码。

形参和实参

不止 Python,几乎所有的编程语言都会涉及两个术语:parameter 和 argument。那么,它们之间究竟有什么区别呢?

parameter 是指函数定义中的参数,而 argument 指的是函数调用时的实际参数。

简略描述:parameter = 形参(formal parameter), argument = 实参(actual parameter)。

例如,定义一个简单的函数:

>>> def greet(param1, param2):
...   pass
... 
>>> 
>>> greet('Hello', 'Python')

其中,param1 和 param2 是函数的形参,而在函数 greet() 被调用时,传入的('Hello''Python')则是实参。

固定数量参数的函数

到目前为止,关于函数,我们介绍的都是固定数量的参数。来看一个简单的示例:

>>> def greet(say, msg):
...   print(say, msg)
... 
>>> 
>>> greet('Hello', 'Python')
Hello Python

这里,函数 greet() 有两个参数,用两个参数调用这个函数,运行得很顺利,不会有任何错误。

倘若,参数的个数不匹配,会发生什么?

>>> greet() # 没有参数
...
TypeError: greet() missing 2 required positional arguments: 'say' and 'msg'
>>> 
>>> greet('Hi') # 只有一个参数
...
TypeError: greet() missing 1 required positional argument: 'msg'

显然,解释器会发牢骚。但是,对 Python 来说,要解决这个问题简直是易如反掌,继续往下看!

默认参数

定义函数时,可以使用赋值运算符(=)为参数指定一个默认值。

注意: 如果参数没有默认值,在调用时必需为其指定一个值;如果参数有默认值,那么在调用时值是可选的,如果为其提供了一个值,将会覆盖默认值。

>>> def greet(say, name = 'James', msg = 'I am your biggest fan!'):
...   print(say, ',', name, ',', msg)
... 
>>> greet('Hi') # 只提供强制性的参数
Hi , James , I am your biggest fan!
>>> 
>>> greet('Hi', 'Kobe') # 给出一个可选参数
Hi , Kobe , I am your biggest fan!
>>> 
>>> greet('Hi', 'Kobe', 'I want to challenge you!') # 给出所有参数
Hi , Kobe , I want to challenge you!

由于 say 没有默认值,所以必须指定;name、msg 有默认值,所以值是可选的。

函数中的所有参数都可以有默认值,但是,一旦存在一个默认参数,其右侧的所有参数也必须有默认值。也就是说,非默认参数不能在默认参数之后。

例如,将上面的函数定义为:

def greet(name = 'James', say):

就会引发错误:

SyntaxError: non-default argument follows default argument

关键字参数

当使用某些值调用函数时,这些值将根据其位置分配给参数。

例如,在上述函数 greet() 中,当使用 greet('Hi', 'Kobe') 调用它时,'Hi' 被赋值给参数 say,同样地,'Kobe' 被赋值给 name。

Python 允许使用 kwarg = value 格式的关键字参数调用函数:

>>> def greet(say, name = 'James'):
...   print(say, ',', name)
... 
>>> 
>>> greet(say = 'Hi', name = 'Kobe') # 2 个关键字参数
Hi , Kobe
>>> 
>>> greet(name = 'Kobe', say = 'Hi') # 2 个关键字参数(次序颠倒)
Hi , Kobe
>>> 
>>> greet('Hi', name = 'Kobe') # 位置参数与关键字参数混合使用
Hi , Kobe

当以这种方式调用函数时,关键字参数必须在位置参数之后,所有传递的关键字参数都必须与函数接受的某个参数匹配,并且它们的顺序不重要。

例如,像下面这样调用,会引发错误:

>>> greet(name = 'Kobe', 'Hi') # 关键字参数在位置参数之前
...
SyntaxError: positional argument follows keyword argument
>>>
>>> greet('Hi', na = 'Kobe') # na 不匹配
...
TypeError: greet() got an unexpected keyword argument 'na'

可变参数

可变参数也被称为不定长参数,顾名思义,就是传入的参数个数是可变的,可以是任意个(0、1、2 … N)。

要定义可变参数,仅需在参数名之前添加一个星号(*)。在函数内部,这些参数被包装为一个 tuple

注意: 此 * 非彼 *,不要误认为是 C/C++ 中的指针。

>>> def greet(*names):
...   print(names)
... 
>>> 
>>> greet() # 没有参数,返回空元组
()
>>>
>>> greet('Jordan', 'James', 'Kobe')
('Jordan', 'James', 'Kobe')

有时,必须在函数定义中使用位置参数以及可变参数,但位置参数始终必须在可变参数之前。

>>> def greet(say, *names):
...   print(say, names)
... 
>>> 
>>> greet('Hi')
Hi ()
>>> 
>>> greet('Hi', 'Jordan', 'James', 'Kobe')
Hi ('Jordan', 'James', 'Kobe')

通常情况下,可变参数会出现在形参列表的最后,因为它们会把传递给函数的所有剩余输入参数都收集起来。可变参数之后出现的任何形参都是“强制关键字”参数,这意味着,它们只能被用作关键字参数,而不能是位置参数。

>>> def greet(*names, sep = ','):
...   return sep.join(names)
... 
>>> 
>>> greet('Jordan', 'James', 'Kobe')
'Jordan,James,Kobe'
>>> 
>>> greet('Jordan', 'James', 'Kobe', sep = '/') # 被用作关键字参数
'Jordan/James/Kobe'
>>>
>>> greet('Jordan', 'James', 'Kobe', '/') # 被用作位置参数
'Jordan,James,Kobe,/'

任意关键字参数

还有一种机制,用于任意数量的关键字参数。为了做到这一点,使用双星号(**):

>>> def greet(**all_star):
...   print(all_star)
... 
>>> greet() # 没有参数,返回空字典
{}
>>> 
>>> greet(name = 'James', age = 18)
{'name': 'James', 'age': 18}

当最后一个形式为 **msgs 的形参出现时,它将收到一个字典,其中包含所有关键字参数,除了与形参对应的关键字参数之外。还可以与 *names 的形参相结合(*names 必须出现在 **msgs 之前)。

例如,定义一个这样的函数:

>>> def greet(say, *names, **msgs):
...   print('--', say)
...   for name in names:
...     print(name)
...   print('-' * 40)
...   keys = sorted(msgs.keys())
...   for key in keys:
...     print(key, ':', msgs[key])
... 
>>> 
>>> greet('Hi', 'Jordan', 'James', 'Kobe', msg = 'I want to challenge you!', challenger = 'Waleon')
-- Hi
Jordan
James
Kobe
----------------------------------------
challenger : Waleon
msg : I want to challenge you!

注意: 在打印内容之前,通过对 msgs 字典的 keys() 方法的结果进行排序来创建关键字参数名称列表。如果没有这样做,则打印参数的顺序是未定义的。

对参数进行解包

正如“可变参数”那样,也可在函数调用中使用 * 操作符。只不过在这种情况下,与在函数定义中 * 的语义相反,参数将被解包而不是打包。

>>> def greet(name, age):
...   print(name, age)
... 
>>> 
>>> t = ('James', 18)
>>> greet(*t)
James 18

还有一种方式,几乎没有必要提到,这里也罗嗦一下:

>>> greet(t[0], t[1])
James 18

与解包相比,这种调用方式显然不舒适。另外,在一般情况下,调用 greet(t[0], t[1]) 几乎是徒劳的,因为长度是未知的。“未知”的意思是:长度只在运行时才知道,而不是在编写脚本时就知道。

同样地,字典也可以用 ** 操作符传递关键字参数:

>>> def greet(name, age = 18):
...   print(name, age)
... 
>>> 
>>> d = {'name':'James', 'age':32}
>>> greet(**d)
James 32

Python获取函数参数个数:

Python2.7写法:

# -*- coding:utf-8 -*-
#! python2
def abc(a,b,c):
  print a,b
yy=abc.func_code.co_argcount
print yy

输出结果为

3

python3.6写法

# -*- coding:utf-8 -*-
#! python3
def abc(a,b,c):
  print(a,b)
a=abc.__code__.co_argcount
print(a)

输出结果为

3

使用场景:

比如在REST规范的代码中,request数据格式检验,判断携带参数个数是否符合该函数所需参数的个数,不是就可以return error了

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
python服务器与android客户端socket通信实例
Nov 12 Python
解密Python中的描述符(descriptor)
Jun 03 Python
matplotlib绘图实例演示标记路径
Jan 23 Python
python3中获取文件当前绝对路径的两种方法
Apr 26 Python
浅谈python中requests模块导入的问题
May 18 Python
python3学生名片管理v2.0版
Nov 29 Python
Python基本语法之运算符功能与用法详解
Oct 22 Python
Django单元测试中Fixtures用法详解
Feb 25 Python
Python GUI库PyQt5图形和特效样式QSS介绍
Feb 25 Python
Python爬取YY评级分数并保存数据实现过程解析
Jun 01 Python
解决Keras TensorFlow 混编中 trainable=False设置无效问题
Jun 28 Python
教你漂亮打印Pandas DataFrames和Series
May 29 Python
利用python打开摄像头及颜色检测方法
Aug 03 #Python
numpy添加新的维度:newaxis的方法
Aug 02 #Python
numpy.ndarray 交换多维数组(矩阵)的行/列方法
Aug 02 #Python
对numpy中的transpose和swapaxes函数详解
Aug 02 #Python
Numpy 改变数组维度的几种方法小结
Aug 02 #Python
python 字典中取值的两种方法小结
Aug 02 #Python
python 剪切移动文件的实现代码
Aug 02 #Python
You might like
ThinkPHP之N方法实例详解
2014/06/20 PHP
php基于curl扩展制作跨平台的restfule 接口
2015/05/11 PHP
PHP自定义函数实现数组比较功能示例
2017/10/19 PHP
三个思路解决laravel上传文件报错:413 Request Entity Too Large问题
2017/11/13 PHP
PHP date_default_timezone_set()设置时区操作实例分析
2020/05/16 PHP
防止浏览器记住用户名及密码的简单实用方法
2013/04/22 Javascript
jquery中ajax函数执行顺序问题之如何设置同步
2014/02/28 Javascript
window.location.href IE下跳转失效的解决方法
2014/03/27 Javascript
使用jquery实现放大镜效果
2014/09/02 Javascript
JavaScript实现点击按钮直接打印
2016/01/06 Javascript
jquery中键盘事件小结
2016/02/24 Javascript
原生JS实现网络彩票投注效果
2016/09/25 Javascript
深入理解JavaScript创建对象的多种方式以及优缺点
2017/06/01 Javascript
详解JavaScript中的六种错误类型
2017/09/21 Javascript
js判断文件类型大小并给出提示的实现方法
2018/01/03 Javascript
vue+vant实现商品列表批量倒计时功能
2020/01/13 Javascript
详谈vue中router-link和传统a链接的区别
2020/07/22 Javascript
JavaScript canvas实现文字时钟
2021/01/10 Javascript
[03:44]2015国际邀请赛选手档案—Cloud9.NoTail
2015/07/28 DOTA
[52:31]VP vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
Python在不同目录下导入模块的实现方法
2017/10/27 Python
对matplotlib改变colorbar位置和方向的方法详解
2018/12/13 Python
对python中if语句的真假判断实例详解
2019/02/18 Python
wxpython+pymysql实现用户登陆功能
2019/11/19 Python
python 提高开发效率的5个小技巧
2020/10/19 Python
美国豪华的多品牌精品店:The Webster
2019/07/31 全球购物
用C#语言写出在本地创建一个UDP接收端口的具体过程
2016/02/22 面试题
交通专业个人自荐信格式
2013/09/23 职场文书
体育教育毕业生自荐信
2013/11/21 职场文书
《诺贝尔》教学反思
2014/02/17 职场文书
共产党员公开承诺书范文
2014/03/28 职场文书
销售口号大全
2014/06/11 职场文书
学生上课看漫画的检讨书
2014/09/26 职场文书
电子商务实训报告总结
2014/11/05 职场文书
2014年创卫工作总结
2014/11/24 职场文书
2015年七夕情人节感言
2015/08/03 职场文书