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 相关文章推荐
如何解决django配置settings时遇到Could not import settings 'conf.local'
Nov 18 Python
在Python的web框架中中编写日志列表的教程
Apr 30 Python
Python爬虫辅助利器PyQuery模块的安装使用攻略
Apr 24 Python
在win和Linux系统中python命令行运行的不同
Jul 03 Python
Python enumerate索引迭代代码解析
Jan 19 Python
Python socket套接字实现C/S模式远程命令执行功能案例
Jul 06 Python
详解Python中的内建函数,可迭代对象,迭代器
Apr 29 Python
浅谈Python访问MySQL的正确姿势
Jan 07 Python
如何基于python实现归一化处理
Jan 20 Python
解决python虚拟环境切换无效的问题
Apr 30 Python
解决pycharm修改代码后第一次运行不生效的问题
Feb 06 Python
解析python中的jsonpath 提取器
Jan 18 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
php的一个登录的类 [推荐]
2007/03/16 PHP
php通过function_exists检测函数是否存在的方法
2015/03/18 PHP
Laravel 中获取上一篇和下一篇数据
2015/07/27 PHP
PHP结合Jquery和ajax实现瀑布流特效
2016/01/07 PHP
php基于协程实现异步的方法分析
2019/07/17 PHP
Javascript 圆角div的实现代码
2009/10/15 Javascript
DOM_window对象属性之--clipboardData对象操作代码
2011/02/03 Javascript
JS焦点图切换,上下翻转
2011/05/12 Javascript
javascript简单事件处理和with用法介绍
2013/09/16 Javascript
解决jquery版本冲突的有效方法
2014/09/02 Javascript
Javascript基础知识(三)BOM,DOM总结
2014/09/29 Javascript
用简洁的jQuery方法toggleClass实现隔行换色
2014/10/22 Javascript
jQuery实现的可编辑表格完整实例
2016/06/20 Javascript
深入理解JS正则表达式---分组
2016/07/18 Javascript
基于Node.js + WebSocket打造即时聊天程序嗨聊
2016/11/29 Javascript
JS树形菜单组件Bootstrap TreeView使用方法详解
2016/12/21 Javascript
jQuery扩展方法实现Form表单与Json互相转换的实例代码
2018/09/05 jQuery
详解vuex commit保存数据技巧
2018/12/25 Javascript
详解vue更改头像功能实现
2019/04/28 Javascript
vue使用openlayers实现移动点动画
2020/09/24 Javascript
微信小程序实现登录注册功能
2020/12/29 Javascript
python3.0 模拟用户登录,三次错误锁定的实例
2017/11/02 Python
使用python将图片格式转换为ico格式的示例
2018/10/22 Python
python 实现敏感词过滤的方法
2019/01/21 Python
解决Pycharm 包已经下载,但是运行代码提示找不到模块的问题
2019/08/31 Python
django 实现celery动态设置周期任务执行时间
2019/11/19 Python
一文读懂Python 枚举
2020/08/25 Python
爱他美官方海外旗舰店:Aptamil奶粉
2017/12/22 全球购物
美国运动鞋和服装网上商店:YCMC
2018/09/15 全球购物
ParcelABC西班牙:包裹运送和快递服务
2019/12/24 全球购物
孝老爱亲模范事迹
2014/01/24 职场文书
门前三包责任书
2014/04/15 职场文书
化学专业自荐信
2014/05/28 职场文书
人口与计划生育责任书
2015/05/09 职场文书
十个Python自动化常用操作,即拿即用
2021/05/10 Python
Go gorilla securecookie库的安装使用详解
2022/08/14 Golang