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 相关文章推荐
tornado捕获和处理404错误的方法
Feb 26 Python
python写入中英文字符串到文件的方法
May 06 Python
python 函数传参之传值还是传引用的分析
Sep 07 Python
python2.7读取文件夹下所有文件名称及内容的方法
Feb 24 Python
Python中的pack和unpack的使用
Mar 12 Python
python3 kmp 字符串匹配的方法
Jul 07 Python
python pygame实现五子棋小游戏
Oct 26 Python
Python re 模块findall() 函数返回值展现方式解析
Aug 09 Python
python 内置函数汇总详解
Sep 16 Python
Python高阶函数、常用内置函数用法实例分析
Dec 26 Python
Python猴子补丁知识点总结
Jan 05 Python
Windows 下python3.8环境安装教程图文详解
Mar 11 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
解析argc argv在php中的应用
2013/06/24 PHP
Aster vs KG BO3 第二场2.18
2021/03/10 DOTA
浅析javascript闭包 实例分析
2010/12/25 Javascript
ASP.NET中AJAX 调用实例代码
2012/05/03 Javascript
用jQuery与JSONP轻松解决跨域访问的问题
2014/02/04 Javascript
iframe里使用JavaScript控制主页转向的方法
2015/04/03 Javascript
jQuery原型属性和原型方法详解
2015/07/07 Javascript
jQuery基于$.ajax设置移动端click超时处理方法
2016/05/14 Javascript
完美的js div拖拽实例代码
2016/09/24 Javascript
聊一聊JS中的prototype
2016/09/29 Javascript
微信js-sdk预览图片接口及从拍照或手机相册中选图接口用法示例
2016/10/13 Javascript
vue组件如何被其他项目引用
2017/04/13 Javascript
js实现放大镜特效
2017/05/18 Javascript
javascript 封装Date日期类实例详解
2017/05/28 Javascript
IntelliJ IDEA 安装vue开发插件的方法
2017/11/21 Javascript
JS中的回调函数实例浅析
2018/03/21 Javascript
vue自定义指令实现仅支持输入数字和浮点型的示例
2019/10/30 Javascript
[02:36]DOTA2上海特锦赛 回忆电竞生涯的重要瞬间
2016/03/25 DOTA
浅谈python和C语言混编的几种方式(推荐)
2017/09/27 Python
Python实现的将文件每一列写入列表功能示例【测试可用】
2018/03/19 Python
python自动保存百度盘资源到百度盘中的实例代码
2019/08/26 Python
使用python-opencv读取视频,计算视频总帧数及FPS的实现
2019/12/10 Python
linux mint中搜狗输入法导致pycharm卡死的问题
2020/10/28 Python
python+opencv3.4.0 实现HOG+SVM行人检测的示例代码
2021/01/28 Python
HTML5 标准将把互联网视频扔回到黑暗时代
2010/02/10 HTML / CSS
美赞臣营养马来西亚旗舰店:Enfagrow马来西亚
2019/07/26 全球购物
业务员自荐信范文
2014/04/20 职场文书
小学生母亲节演讲稿
2014/05/07 职场文书
工作会议方案
2014/05/21 职场文书
新农村建设典型材料
2014/05/31 职场文书
李白故里导游词
2015/02/12 职场文书
老员工辞职信范文
2015/05/12 职场文书
运动会通讯稿300字
2015/07/20 职场文书
2016寒假假期总结
2015/10/10 职场文书
心理健康教育培训研修感言
2015/11/18 职场文书
Springboot集成阿里云OSS上传文件系统教程
2021/06/28 Java/Android