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操作excel的方法(xlsxwriter包的使用)
Jun 11 Python
解决python opencv无法显示图片的问题
Oct 28 Python
Python判断telnet通不通的实例
Jan 26 Python
解决Python内层for循环如何break出外层的循环的问题
Jun 24 Python
Django框架静态文件使用/中间件/禁用ip功能实例详解
Jul 22 Python
python实现将json多行数据传入到mysql中使用
Dec 31 Python
Pytorch在dataloader类中设置shuffle的随机数种子方式
Jan 14 Python
基于python3生成标签云代码解析
Feb 18 Python
如何将tensorflow训练好的模型移植到Android (MNIST手写数字识别)
Apr 22 Python
基于Python pyecharts实现多种图例代码解析
Aug 10 Python
如何通过python计算圆周率PI
Nov 11 Python
BeautifulSoup获取指定class样式的div的实现
Dec 07 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
yii2缓存Caching基本用法示例
2016/07/18 PHP
详解Laravel视图间共享数据与视图Composer
2016/08/04 PHP
PHP开发的微信现金红包功能示例
2017/06/29 PHP
讨论html与javascript在浏览器中的加载顺序问题
2013/11/27 Javascript
常用的jquery模板插件——jQuery Boilerplate介绍
2014/09/23 Javascript
Json实现异步请求提交评论无需跳转其他页面
2014/10/11 Javascript
JS实现点击颜色块切换指定区域背景颜色的方法
2015/02/25 Javascript
JavaScript数组迭代器实例分析
2015/06/09 Javascript
JS使用cookie实现DIV提示框只显示一次的方法
2015/11/05 Javascript
基于javascript实现动态时钟效果
2020/08/18 Javascript
jquery分隔Url的param方法(推荐)
2016/05/25 Javascript
AngularJs学习第八篇 过滤器filter创建
2016/06/08 Javascript
前端js实现文件的断点续传 后端PHP文件接收
2016/10/14 Javascript
详解在Angularjs中ui-sref和$state.go如何传递参数
2017/04/24 Javascript
详解AngularJS 路由 resolve用法
2017/04/24 Javascript
AngularJS实现的获取焦点及失去焦点时的表单验证功能示例
2017/10/25 Javascript
详解如何在微信小程序中愉快地使用sass
2018/07/30 Javascript
使用webpack搭建vue项目及注意事项
2019/06/10 Javascript
详解Nuxt内导航栏的两种实现方式
2020/04/16 Javascript
jQuery+Ajax+js实现请求json格式数据并渲染到html页面操作示例
2020/06/02 jQuery
JS实现可以用键盘方向键控制的动画
2020/12/11 Javascript
[14:20]刀塔大凶女神互压各路奇葩屌丝
2014/05/16 DOTA
[56:18]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#2 MVP.Phx VS Fnatic第二局
2016/03/05 DOTA
[40:05]LGD vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/18 DOTA
用Python编写简单的定时器的方法
2015/05/02 Python
Python操作Access数据库基本步骤分析
2016/09/19 Python
python win32 简单操作方法
2017/05/25 Python
python+splinter自动刷新抢票功能
2018/09/25 Python
django多种支付、并发订单处理实例代码
2019/12/13 Python
基于Python生成个性二维码过程详解
2020/03/05 Python
W Concept美国:精选全球独立设计师
2017/02/22 全球购物
伦敦一家西班牙童装精品店:La Coqueta
2018/02/02 全球购物
小区停车场管理制度
2014/01/27 职场文书
城市规划应届毕业生自荐信
2014/07/04 职场文书
2014离婚协议书范文
2014/09/10 职场文书
浅谈:电影《孔子》观后感(范文)
2019/10/14 职场文书