详解Python函数参数定义及传参(必备参数、关键字参数、默认可省略参数、可变不定长参数、*args、**kwargs)_函数参数传递python-程序员宅基地

技术标签: 可变参数  变长参数  Python语言  Python  

详解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中函数的不同类型参数的区别及应用场景例举,一点心得体会,希望对有兴趣的朋友能有所帮助!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yyykj/article/details/103122665

智能推荐

while循环&CPU占用率高问题深入分析与解决方案_main函数使用while(1)循环cpu占用99-程序员宅基地

文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。​​​​​​while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99

【无标题】jetbrains idea shift f6不生效_idea shift +f6快捷键不生效-程序员宅基地

文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效

node.js学习笔记之Node中的核心模块_node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是-程序员宅基地

文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是

数学建模【SPSS 下载-安装、方差分析与回归分析的SPSS实现(软件概述、方差分析、回归分析)】_化工数学模型数据回归软件-程序员宅基地

文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件

利用hutool实现邮件发送功能_hutool发送邮件-程序员宅基地

文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件

docker安装elasticsearch,elasticsearch-head,kibana,ik分词器_docker安装kibana连接elasticsearch并且elasticsearch有密码-程序员宅基地

文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码

随便推点

Python 攻克移动开发失败!_beeware-程序员宅基地

文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware

Swift4.0_Timer 的基本使用_swift timer 暂停-程序员宅基地

文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停

元素三大等待-程序员宅基地

文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待

Java软件工程师职位分析_java岗位分析-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析

Java:Unreachable code的解决方法_java unreachable code-程序员宅基地

文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code

标签data-*自定义属性值和根据data属性值查找对应标签_如何根据data-*属性获取对应的标签对象-程序员宅基地

文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象

推荐文章

热门文章

相关标签