详解Python函数参数定义及传参(必备参数、关键字参数、默认可省略参数、可变不定长参数、*args、**kwargs)

Python函数参数传参的种类

  Python中函数参数定义及调用函数时传参大体可分必备参数、关键字参数、默认可省略参数、不定长元组参数、不定长关键字参数等,下面通过函数定义及调用上的不同情况深入解析这些中参数的不同及应用场景。

  为了更好的理解不同参数的具体意义,所以下面演示代码中,使用的参数数量较多。具体是一个调用MySQL数据库配置参数的函数所需要的参数,我们用这个来演示不同类型的特点及适用方法,了解每种类型的应用场景及优缺点。

必备参数__仅赋值传参

  必备参数,就是在调用函数的时候,定义的参数要全部都有赋值,否则执行的时候代码会报错。

#!/usr/bin/env python
# -*- coding: utf-8 -*- # 演示获得数据库配置参数,使用必备参数
def demo_get_conf1(user, pw, host, port, db, charset):
"打印得到的数据库配置"
print('host: ', host)
print('port: ', port)
print('user: ', user)
print('pw: ', pw)
print('db: ', db)
print('charset: ', charset) demo_get_conf1('root', '1234', '127.0.0.1', '3306', 'tests', 'utf8')

  上述代码中,调用demo_get_conf1函数的时候,定义的所有参数都必须传递,并且要按照规定的顺序传递,否则函数体内得到的也是错误的。以上代码控制台输出:

host:  127.0.0.1
port: 3306
user: root
pw: 1234
db: tests
charset: utf8

  这也是我们希望得到的正确结果。

  下面我们把上述代码最后一行调用的前两个参数("root"和"1234")对调一下:

demo_get_conf1('1234', 'root', '127.0.0.1', '3306', 'tests', 'utf8')

  执行后控制台输出:

host:  127.0.0.1
port: 3306
user: 1234
pw: root
db: tests
charset: utf8

  很显然,得到的 user 变成了 1234,pw 变成了 root,也就是说是完全按照位置来对应函数定义时的参数变量,所以传参的时候,顺序不能错,参数比较多的时候,就不容易记住顺序了。那么Python还给大家一种传递方式,同样是上面的函数,可以不用按顺序传参,请看下节“必备参数__键值对传参”。

必备参数__键值对传参(关键字参数)

  同样是必备参数,但是在代用函数传参的时候,可以直接使用键值对的方式,看下面演示代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*- # 演示获得数据库配置参数,使用必备参数
def demo_get_conf1(user, pw, host, port, db, charset):
"打印得到的数据库配置"
print('host: ', host)
print('port: ', port)
print('user: ', user)
print('pw: ', pw)
print('db: ', db)
print('charset: ', charset) demo_get_conf1(
charset='utf8',
pw='1234',
user='root',
host='127.0.0.1',
port='3306',
db='tests')

  控制台输出:

host:  127.0.0.1
port: 3306
user: root
pw: 1234
db: tests
charset: utf8

  函数定义还是与上例一样,只是调用函数的时候,参数传递使用了键值对,键名就是参数定义时的变量名,这样就可以不用理会顺序,只要记住键名(参数变量名)就可以了。

  但是这毕竟是必备参数,所有的参数都要传递,否则会报错,例如将调用修改成:

demo_get_conf1(
pw='1234',
user='root',
host='127.0.0.1',
port='3306',
db='tests')

  控制台会输出:

TypeError: demo_get_conf1() missing 1 required positional argument: 'charset'

  提示缺少'charset'参数,代码不能正常运行。那么有没有可以缺省参数,用就传递,不用就不传递的,Python肯定也有这种参数,继续看下一节“默认可省略参数”。

默认可省略参数

  默认可省略参数,就是在定义的时候就给了默认值,如果在函数调用的时候给这个参数传值了,那么就使用传递的值,如果没有传递就使用定义时候的默认值。

#!/usr/bin/env python
# -*- coding: utf-8 -*- # 演示获得数据库配置参数,使用默认可省略参数
def demo_get_conf2(user, pw, host, port, db, charset='utf8'):
"打印得到的数据库配置"
print('host: ', host)
print('port: ', port)
print('user: ', user)
print('pw: ', pw)
print('db: ', db)
print('charset: ', charset) demo_get_conf2('root', '1234', '127.0.0.1', '3306', 'tests')

  在上述代码中,调用demo_get_conf2函数的时候,我们并没有传递第六个参数charset,但是代码没有报错,控制台输出:

host:  127.0.0.1
port: 3306
user: root
pw: 1234
db: tests
charset: utf8

  可见参数"charset"虽然在调用的时候没有传递,但是依然得到了值"utf8",这个值就是在函数定义时候,参数"charset"赋值的默认值。

  但是这个参数必须在后面,否则调用的时候按照顺序赋值的时候,少传递一个就不是这个有默认值的了,所以Python不允许那样做,看下面的例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*- # 演示获得数据库配置参数,使用默认可省略参数
def demo_get_conf1(user, pw, host, port, db='tests', charset):
"打印得到的数据库配置"
print('host: ', host)
print('port: ', port)
print('user: ', user)
print('pw: ', pw)
print('db: ', db)
print('charset: ', charset) demo_get_conf1('root', '1234', '127.0.0.1', '3306', 'tests')

  控制台输出:

SyntaxError: non-default argument follows default argument

  提示非默认参数不能在默认参数之后,代码不能正常执行。

  有些时候,我们不能确定要具体传递几个参数,应用场景需要的参数数量差异较大,那么是否可以动态传递不同数量的参数呢,继续看下一节“可变长元组参数”

不定长元组参数(*args)

  不定长元组参数,就是不确定数量的参数,定义一个参数把传入的参数组合成元组,来接收函数调用时传递过来的N个参数,在函数体内以元组形式按顺序读取。为了演示更多是使用场景,下面没有使用网络中通常使用的循环方式来取可变长元组参数。

#!/usr/bin/env python
# -*- coding: utf-8 -*- # 演示获得数据库配置参数,使用可变长元组参数
def demo_get_conf3(host, port, *cnf):
"打印得到的数据库配置"
print('host: ', host)
print('port: ', port)
print('user: ', cnf[0])
print('pw: ', cnf[1])
print('db: ', cnf[2])
print('charset: ', cnf[3]) demo_get_conf3('127.0.0.1', '3306', 'root', '1234', 'tests', 'utf8')

控制台输出:

host:  127.0.0.1
port: 3306
user: root
pw: 1234
db: tests
charset: utf8

  可见这是我们正常需要得到的结果,可以多传更多的参数,只要里面取值的数量没有超过传递过来可变参数的数量,就不会报错。

  在上例中,host 和 port 是必备参数,函数调用的时候,在这两个参数后面所传递的,就都是对应到函数定义时的变长参数元组里了。

  在Python中,函数参数是可以使用元组的,那么这总定义与直接使用元组参数有什么区别呢,下面看使用元组参数的示例:

#!/usr/bin/env python
# -*- coding: utf-8 -*- # 演示获得数据库配置参数,使用元组参数
def demo_get_conf4(host, port, cnf):
"打印得到的数据库配置"
print('host: ', host)
print('port: ', port)
print('user: ', cnf[0])
print('pw: ', cnf[1])
print('db: ', cnf[2])
print('charset: ', cnf[3]) demo_get_conf4('127.0.0.1', '3306', ('root', '1234', 'tests', 'utf8'))

  控制台输出:

host:  127.0.0.1
port: 3306
user: root
pw: 1234
db: tests
charset: utf8

  与上一例比,函数体一模一样,参数 cnf 只是少了个 “*”。重点是调用的时候不同,可以看出明显的区别,可变长元组参数在调用的时候,可以与必备参数一样依次传递,而定义元组类型参数,调用函数传递参数时,需要传递元组类型的数据才可以。

  这种参数传递的时候,元组里面的元素也是要强调顺序的,如果是累加一类的函数,顺序不重要,如果是每个元素都代表不同具体含义的,那顺序就十分重要,不可以搞错,否则与必备参数一样,会在函数体内取值错误。

  在上两例中,只能算是元组参数,还不能算不定长,因为函数体内的取值规定了元组的元素数量,那接下来看一个网络上通常写法的例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*- # 演示获得数据库配置参数,使用可变长元组参数
def demo_get_conf5(x, y, *nums):
"得到累加和"
res = x + y
for i in nums:
res += i
return res print(demo_get_conf5(10, 20,))
print(demo_get_conf5(10, 20, 15, 25, 30))
print(demo_get_conf5(10, 20, 15, 25, 30, 50, 30))

  控制台输出:

30
100
180

  上例中,前两个参数是必须传的,后面的参数可传可不传,传的数量也不固定,根据需要由外部调用决定,所以这是可变长参数。但是这种应用适合元组内参数是相同类型和作用,如果回到上面的配置参数应用中,是否可以不定长的呢,看下面的代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*- # 演示获得数据库配置参数,使用可变长元组参数
def demo_get_conf6(host, port, *cnf):
"打印得到的数据库配置"
arr = ['root', '1234', 'tests', 'utf8'] # 可变参数的默认值
len_arr = len(arr)
len_cnf = len(cnf)
if len_cnf > len_arr:
len_cnf = len_arr # 取变长参数最多不超过默认列表中的数量,多余的忽略 for i in range(len_cnf):
arr[i] = cnf[i] print('host: ', host)
print('port: ', port)
print('user: ', arr[0])
print('pw: ', arr[1])
print('db: ', arr[2])
print('charset: ', arr[3]) print('\n', '传递5个变长参数')
demo_get_conf6('127.0.0.1', '3306', 'new_user', '5678', 'tests', 'utf8mb4', 'abc')
print('\n', '传递4个变长参数')
demo_get_conf6('127.0.0.1', '3306', 'new_user', '5678', 'tests', 'utf8mb4')
print('\n', '传递2个变长参数')
demo_get_conf6('127.0.0.1', '3306', 'new_user', '5678')
print('\n', '不传递变长参数')
demo_get_conf6('127.0.0.1', '3306')

  控制台输出:

 传递5个变长参数
host: 127.0.0.1
port: 3306
user: new_user
pw: 5678
db: tests
charset: utf8mb4 传递4个变长参数
host: 127.0.0.1
port: 3306
user: new_user
pw: 5678
db: tests
charset: utf8mb4 传递2个变长参数
host: 127.0.0.1
port: 3306
user: new_user
pw: 5678
db: tests
charset: utf8 不传递变长参数
host: 127.0.0.1
port: 3306
user: root
pw: 1234
db: tests
charset: utf8

  可以看出,传递5个变长参数的,多出那个“abc”参数被忽略掉了,余下的四个参数都按照传递的值取到了;传递4个变长参数的,完全吻合,得到的都是传递的参数;传递2个变长参数的,前两个变长参数是调用传输时传递的值,后两个则是使用的默认值;不传递变长参数的,变长参数全部使用了默认值。这就实现了不同用途的变长参数取值并都可以设置默认值的目的,在一定范围内实现了不定长。

  但是这种变长参数,都还是要保证传递顺序的,元组里的顺序如果传递错误,对于后面例子那获取的数据就是错误的。是否可以不定长有不用理会顺序呢,继续看下一节“不定长字典参数”。

不定长字典参数(**kwargs)

  不定长字典参数,就是不确定数量的参数,定义一个字典,按键值对形式来接收函数调用时传递过来的N个参数,在函数体内以字典形式按键值对读取。这样在传递的时候,就可以不用在意顺序问题了,看下面的代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*- # 演示获得数据库配置参数,使用可变长字典参数
def demo_get_conf7(host, port, **cnf):
"打印得到的数据库配置"
print('host: ', host)
print('port: ', port)
print('user: ', cnf['user'])
print('pw: ', cnf['pw'])
print('db: ', cnf['db'])
print('charset: ', cnf['charset']) demo_get_conf7('127.0.0.1', '3306', user='new_user', pw='5678', db='tests', charset='utf8mb4')

  控制台输出:

host:  127.0.0.1
port: 3306
user: new_user
pw: 5678
db: tests
charset: utf8mb4

  在上述代码中,可以看出,在函数体内实际把**cnf参数当做字典来读取,那么与把函数参数直接定义成字典来用相比较,对函数体内是没有区别的,但是在函数调用的时候,参数传递就有差别了。如果参数定义成字典,那么调用的时候就需要传递字典,否则会报错,如下面代码:

# 演示获得数据库配置参数,使用字典参数
def demo_get_conf7(host, port, cnf):
"打印得到的数据库配置"
print('host: ', host)
print('port: ', port)
print('user: ', cnf['user'])
print('pw: ', cnf['pw'])
print('db: ', cnf['db'])
print('charset: ', cnf['charset']) demo_get_conf7('127.0.0.1', '3306', {'user':'new_user', 'pw':'5678', 'db':'tests', 'charset':'utf8mb4'})

  与上一例比,函数体一模一样,参数 cnf 只是少了两个 “*”。重点是调用的时候不同,可以看出明显的区别,可变长字典参数在调用的时候,可以直接写键名,不用引号,使用“=”赋值,而定义字典类型参数,调用函数传递参数时,需要传递字典类型的数据才可以。

  在上线的例子中,函数体内的代码变相等于指定了不定长参数**cnf的长度,但参数是可以变长的是确定的,主要是函数体里面取值的代码逻辑。如果循环打印输出,就可以任意变长,但是实际项目中这样做适用场景不多。还是取数据库配置这个需求,我们改写一下函数体的代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*- # 演示获得数据库配置参数,使用字典参数
def demo_get_conf7(host, port, **cnf):
"打印得到的数据库配置"
arr = {'user': 'root', 'pw': '1234', 'db': 'tests', 'charset': 'utf8'} # 可变参数的默认值 for key, val in cnf.items():
if key in arr:
arr[key] = val # 取变长参数传递过来的键,如果在预置里面存在就更改,不存在的忽略 print('host: ', host)
print('port: ', port)
print('user: ', arr['user'])
print('pw: ', arr['pw'])
print('db: ', arr['db'])
print('charset: ', arr['charset']) print('----------参数完整传递:')
demo_get_conf7('127.0.0.1', '3306', user='new_user', pw='5678', db='tests', charset='utf8mb4')
print('----------参数多余传递:')
demo_get_conf7('127.0.0.1', '3306', user='new_user', pw='5678', db='tests', charset='utf8mb4', abc='123')
print('----------参数减少传递:')
demo_get_conf7('127.0.0.1', '3306', user='new_user', pw='5678')
print('----------变参没有传递:')
demo_get_conf7('127.0.0.1', '3306')

  控制台输出:

----------参数完整传递:
host: 127.0.0.1
port: 3306
user: new_user
pw: 5678
db: tests
charset: utf8mb4
----------参数多余传递:
host: 127.0.0.1
port: 3306
user: new_user
pw: 5678
db: tests
charset: utf8mb4
----------参数减少传递:
host: 127.0.0.1
port: 3306
user: new_user
pw: 5678
db: tests
charset: utf8
----------变参没有传递:
host: 127.0.0.1
port: 3306
user: root
pw: 1234
db: tests
charset: utf8

  从控制台结果可以看出,多余传递的可变长参数被忽略掉了,少传的可变长参数使用了函数体内的默认值。可变长参数如果一个也没传递,那就完全使用了函数体内的默认值。

  以上是对Python中函数的不同类型参数的区别及应用场景例举,一点心得体会,希望对有兴趣的朋友能有所帮助!

详解Python函数参数定义及传参(必备参数、关键字参数、默认可省略参数、可变不定长参数、*args、**kwargs)的更多相关文章

  1. python 函数的定义及传参

    函数是一个通用的程序结构部件,是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 定义一个简单的函数: >>> def test(a): #创建一个函数,函数名是test ...

  2. 详解python函数的参数

    详解python函数的参数 一.参数的定义 1.函数的参数在哪里定义 在python中定义函数的时候,函数名后面的括号里就是用来定义参数的,如果有多个参数的话,那么参数之间直接用逗号, 隔开 案列: ...

  3. 深入理解PHP内核(十二)函数-函数的定义、传参及返回值

    原文链接:http://www.orlion.ga/344/ 一.函数的定义 用户函数的定义从function 关键字开始,如下 function foo($var) {    echo $var; ...

  4. 深入理解PHP内核(六)函数的定义、传参及返回值

    一.函数的定义 用户函数的定义从function 关键字开始,如下 function foo($var) { echo $var; } 1.词法分析 在Zend/zend_language_scann ...

  5. react router @4 和 vue路由 详解(六)vue怎么通过路由传参?

    完整版:https://www.cnblogs.com/yangyangxxb/p/10066650.html 8.vue怎么通过路由传参? a.通配符传参数 //在定义路由的时候 { path: ' ...

  6. react router @4 和 vue路由 详解(五)react怎么通过路由传参

    完整版:https://www.cnblogs.com/yangyangxxb/p/10066650.html 7.react怎么通过路由传参? a.通配符传参(刷新页面数据不丢失) //在定义路由的 ...

  7. c语言-函数的定义及传参

    模块化编程 定义: 数据类型 函数名(型参):如果没有数据类型,默认的为int 值传递 地址传递 嵌套调用 递归调用:直接或间接调用本身函数,求可能栈破裂,求阶乘 #include <stdio ...

  8. python不定长参数 *argc,**kargcs(19)

    在 python函数的声明和调用 中我们简单的了解了函数的相关使用,然而在函数传递参数的时候,我们埋下了一个坑,关于不定长参数的传递我们还没有讲,今天这篇文章主要就是讲解这个问题. 一.函数不定长参数 ...

  9. 举例详解Python中的split()函数的使用方法

    这篇文章主要介绍了举例详解Python中的split()函数的使用方法,split()函数的使用是Python学习当中的基础知识,通常用于将字符串切片并转换为列表,需要的朋友可以参考下   函数:sp ...

随机推荐

  1. 使用 nginx 实现虚拟主机

    当多个系统需要部署的时候,有系统访问很小,为了节省成本,就需要将多个系统部署到同一台服务器上,怎么在同一台服务器上,完成不同系统的部署和访问,就需要使用虚拟主机实现. 使用端口实现虚拟主机 配置 ng ...

  2. 第六章 jQuery选择器

    jQuery选择器概述: 选择器jQuery基础,在jQuery中,对事件处理,遍历DOM和Ajax操作都依赖于选择器. 什么是jQuery选择器: jQuery选择器拥有良好的浏览器兼容性,不用使用 ...

  3. WebGPU学习(五): 现代图形API技术要点和WebGPU支持情况调研

    大家好,本文整理了现代图形API的技术要点,重点研究了并行和GPU Driven Render Pipeline相关的知识点,调查了WebGPU的相关支持情况. 另外,本文对实时光线追踪也进行了简要的 ...

  4. Day 04 数据类型基础

    目录 什么是数据类型 为什么对数据分类 整型和浮点型统称为数字类型 整型(int) 作用 定义 使用方法 浮点型(float) 作用 定义 使用方法 强制类型转换 什么是字符串 作用 定义 使用方法 ...

  5. mini_magick上传图片

    rails上传图片需要用到的gem: gem 'carrierwave'gem 'mini_magick' 在项目Gemfil中添加上面的两个gem,然后bundle install 然后创建modl ...

  6. 小白学 Python 爬虫(21):解析库 Beautiful Soup(上)

    小白学 Python 爬虫(21):解析库 Beautiful Soup(上) 人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前 ...

  7. MySQL安装及配置最详细教程

    https://blog.csdn.net/Mxdon_on/article/details/89461513 概述 MySQL作为最常用的数据库,手动安装的方法还是稍微有些弯弯 首先下载安装包 (官 ...

  8. Django forms组件与钩子函数

    目录 一.多对多的三种创建方式 1. 全自动 2. 纯手撸(了解) 3. 半自动(强烈推荐) 二.forms组件 1. 如何使用forms组件 2. 使用forms组件校验数据 3. 使用forms组 ...

  9. 《Dotnet9》系列-开源C# Winform控件库强力推荐

    时间如流水,只能流去不流回! 点赞再看,养成习惯,这是您给我创作的动力! 本文 Dotnet9 https://dotnet9.com 已收录,站长乐于分享dotnet相关技术,比如Winform.W ...

  10. 一些实用的 Laravel 小技巧

    Laravel 中一些常用的小技巧,说不定你就用上了. 1.侧栏 网站一般都有侧栏,用来显示分类,标签,热门文章,热门评论啥的,但是这些侧栏都是相对独立的模块,如果在每一个引入侧栏的视图中都单独导入与 ...