当前位置:

首页 > 编程开发 > Python编程:掌握函数输入参数的规则

Python编程:掌握函数输入参数的规则

​本文内容主要涉及如下几个主题方法,文章有点长,请收藏以便查阅。函数参数即为函数的输入,可分类为五组。位置或关键字参数:同时允许位置和关键字参数;可变位置参数:在元组中收集任意数量的位置参数;可变关键字参数:在字典中收集任意数量的关键字参数;仅限位置参数:只能作为位置参数传递;仅限关键字参数:只能作为关键字参数传递。到目前为止,我们所看到的例子中,看到的所有参数都是普通的位置参数或关键字参数。也已经了解了如何将它们作为位置参数和关键字参数传递。关于它们没有太多要说的了,所以我们要来看看其他类别。在此之前,

本文目录

    ​本文内容主要涉及如下几个主题方法,文章有点长,请收藏以便查阅。

    函数参数即为函数的输入,可分类为五组。

    • 位置或关键字参数:同时允许位置和关键字参数;
    • 可变位置参数:在元组中收集任意数量的位置参数;
    • 可变关键字参数:在字典中收集任意数量的关键字参数;
    • 仅限位置参数:只能作为位置参数传递;
    • 仅限关键字参数:只能作为关键字参数传递。

    到目前为止,我们所看到的例子中,看到的所有参数都是普通的位置参数或关键字参数。也已经了解了如何将它们作为位置参数和关键字参数传递。关于它们没有太多要说的了,所以我们要来看看其他类别。在此之前,先来看看可选参数。

    1.可选参数

    除了我们在这里看到的类别之外,参数还可以分为必选项和可选项。可选参数有默认值,其值在函数定义中指定。语法是格式为:name=value。示例如下:

    # 定义参数有默认值的函数,调用时其为可选型参数
    def func(a, b=4, c=88):
    print(a, b, c)
    
    func(1) # prints: 1 4 88
    func(b=5, a=7, c=9) # prints: 7 5 9
    func(42, c=9) # prints: 42 4 9
    func(42, 43, 44) # prints: 42, 43, 44

    这里,a是必需传递参数项,而b的默认值是4,c的默认值是88,两者是可选项。重要的是要注意,除了只有关键字的形参外,必需型形参必须始终位于函数定义中所有可选形参的左侧。试着在上面的例子中删除c的默认值,看看会发生什么。

    2.不定量位置参数

    有时,可能不希望为函数指定位置参数的确切数量,而Python通过使用可变位置参数提供了实现这一点的能力。让我们来看一个非常常见的用例,minimum()函数。

    这是一个计算其输入值最小值的函数,代码如下:

    # 不定量位置参数
    def minimum(*n):
    # print(type(n)) # n 是个元组
    if n: #
    mn = n[0]
    for value in n[1:]:
    if value < mn:
    mn = value
    print(mn)
    
    minimum(1, 3, -7, 9) # n = (1, 3, -7, 9) - prints: -7
    minimum() # n = () - prints: nothing

    如上所见,当我们定义一个带有星号*的形参时,我们是在告诉Python,当函数被调用时,这个形参将收集数量不定的位置实参。在函数中,n是一个元组。可取消代码中的注释print(type(n))行,然后运行程序并看看输出。

    注意,一个函数最多只能有一个不定量位置参数——有更多的位置参数是没有意义的。Python将无法决定如何划分它们之间的参数。您也无法为变量位置参数指定默认值。默认值总是一个空元组。

    提示:

    是否注意到代码中是如何用一个简单的if n:检查n是否为空的?这是因为在Python中,集合对象在非空时求值为True,否则为False。元组、集合、列表、字典等等都是如此。

    另一件需要注意的事情是,当调用不带参数的函数时,可能想抛出一个错误,而不是静默地什么都不做。在这种情况下,我们不关心如何使这个函数健壮,而是要理解可变量位置参数。

    另外,是否注意到,定义不定量位置形参的语法与可迭代解包的语法非常相似?这并非巧合。毕竟,这两个特征互为镜像。它们也经常一起使用,因为不定量位置形参让你不必担心解包的可迭代对象的长度是否与函数定义中的形参数量相匹配。

    3.不定量关键字参数

    不定量关键字参数(Variable keyword parameters)非常类似于不定量位置参数。唯一的区别是语法(**而不是*)和它们以字典形式被收集的事实:

    # 不定量关键字参数
    def func(**kwargs):
    print(kwargs)
    
    func(a=1, b=42) # prints {'a': 1, 'b': 42}
    func() # prints {}
    func(a=1, b=46, c=99) # prints {'a': 1, 'b': 46, 'c': 99}

    如上所示,在函数定义的参数名称前添加**告诉Python使用该名称来收集数量不定的关键字参数。与不定量位置参数的情况一样,每个函数最多只能有一个可变关键字参数,并且不能指定默认值。

    就像可变量位置参数类似于可迭代解包一样,可变关键字参数类似于字典解包。字典解包也经常用于将参数传递给具有可变量关键字形参的函数。

    为什么能够传递可变数量的关键字参数如此重要,目前可能还不清楚,那么通过如何使用这一能力的示例,你将能更真实的理解其重要性。

    我们定义一个连接到数据库的函数:我们希望通过不带参数地调用这个函数来连接到默认数据库。还希望通过向函数传递适当的参数来连接到任何其他数据库。在你继续读下去之前,自己试着花几分钟自己想出一个解决方案:

    # 可变量关键字参数
    def connect(**options):
    conn_params = {
    'host': options.get('host', '127.0.0.1'),
    'port': options.get('port', 5432),
    'user': options.get('user', ''),
    'pwd': options.get('pwd', ''),
    }
    print(conn_params)
    
    # 然后连接数据库(注释掉的代码行)
    # db.connect(**conn_params)
    connect()
    connect(host='127.0.0.42', port=5433)
    connect(port=5431, user='admin', pwd='super')

    注意,在函数中,我们可以准备一个连接参数字典(conn_params)使用默认值作为回退,其允许在函数调用时提供以覆盖它们。有更好的方法可以用更少的代码行来实现这一点,但我们现在不关心这一点。运行上述代码会得到以下结果:

    {'a': 1, 'b': 46, 'c': 99}
    {'host': '127.0.0.1', 'port': 5432, 'user': '', 'pwd': ''}
    {'host': '127.0.0.42', 'port': 5433, 'user': '', 'pwd': ''}
    {'host': '127.0.0.1', 'port': 5431, 'user': 'admin', 'pwd': 'super'}

    注意函数调用和输出之间的对应关系,以及如何根据传递给函数的内容重写默认值。

    4.仅限位置参数

    从Python 3.8开始,PEP 570 (https://www.python.org/dev/peps/pep-0570/)引入了仅限位置的参数。有一种新的函数参数语法,/,表示一组函数形参必须在位置上指定,不能作为关键字参数传递。让我们看一个简单的例子:

    # 仅限位置参数
    def func(a, b, /, c):
    print(a, b, c)
    
    func(1, 2, 3) # prints: 1 2 3
    func(1, 2, c=3) # prints 1 2 3

    在上面的例子中,我们定义了一个函数func(),它指定了三个参数:a、b和c。函数签名中的/表示a和b必须按位置传递,也就是说,不能通过关键字传递。

    示例中的最后两行显示,我们可以按位置传递所有三个参数来调用函数,或者可以按关键字传递c。这两种情况都可以正常工作,因为c定义在函数签名中的/之后。如果我们试图通过通过关键字传递a或b来调用函数,像这样:

    func(1, b=2, c=3)

    这将产生如下类似回溯跟踪信息:

    Traceback (most recent call last):
    File "……", line 9, in 
    func(1, b=2, c=3)
    TypeError: func() got some positional-only arguments passed as keyword arguments: 'b'

    前面的例子告诉我们,Python现在反馈给我们调用func()的方式,其意思是:通过关键字传递了参数b,但不允许这样做。

    仅限位置参数也可以是可选的,如下所示:

    # 可选的仅限位置参数
    def func(a, b=2, /):
    print(a, b)
    
    func(4, 5) # prints 4 5
    func(3) # prints 3 2

    通过一些从官方文档中借来的例子来看看这个特性给该语言带来了什么。一个优点是能够完全模拟现有C编码函数的行为:

    def divmod(a, b, /):
    "模拟内建函数 divmod()"
    return (a // b, a % b)

    另一个重要的用例是在形参名没有啥有意义的帮助的情况下排除关键字实参:

    len(obj='hello')

    在上面的例子中,obj关键字参数降低了可读性。此外,如果我们希望重构len函数的内部结构,并将obj重命名为the_object(或任何其他名称),更改保证不会破坏任何客户端代码,因为不会有任何对len()函数的调用,会涉及到现在已经过时的obj参数名称。

    最后,使用仅限位置形参意味着/左边的任何值都可以在不定量关键字实参中使用,如下例所示:

    def func_name(name, /, **kwargs):
    print(name)
    print(kwargs)
    
    func_name('Positional-only name', name='Name in **kwargs')
    # 打印输出为:
    # Positional-only name
    # {'name': 'Name in **kwargs'}

    在函数签名中保留参数名以便在**kwargs中使用的能力可以生成更简单、更清晰的代码。

    现在来研究一下仅限位置类似版:仅限关键字参数。

    5.仅限关键字参数

    Python 3引入了仅限关键字的参数。我们只简要地研究它们,因为它们的用例并不常见。有两种方法可以指定它们,要么在不定量位置参数之后,要么在不定的*之后。来看两个例子。代码如下:

    # 仅限关键字参数
    def kwo(*a, c):
    print(a, c)
    
    kwo(1, 2, 3, c=7) # prints: (1, 2, 3) 7
    kwo(c=4) # prints: () 4
    # kwo(1, 2) # 此行出问题——无效于法,并有如下错误
    # TypeError: kwo() missing 1 required keyword-only argument: 'c'
    
    def kwo2(a, b=42, *, c):
    print(a, b, c)
    
    kwo2(3, b=7, c=99) # prints: 3 7 99
    kwo2(3, c=13) # prints: 3 42 13
    # kwo2(3, 23) # 此行出问题——无效于法,并有如下错误
    # TypeError: kwo2() missing 1 required keyword-only argument: 'c'

    正如预期的那样,函数kwo()接受数量可变的位置参数(a)和一个只有关键字的关键字c。调用的结果很简单,你可以取消对第三个调用的注释,以查看Python返回什么错误。

    同样的情况也适用于函数kwo2(),它与kwo的不同之处在于,它接受一个位置参数a、一个关键字参数b和一个只有关键字的参数c。你可以取消对第三个调用的注释,以查看产生的错误。

    现在应已知道了如何指定不同类型的输入参数,接下来看看如何在函数定义中组合它们。

    6.组合输入参数

    可以在同一个函数中组合不同的参数类型(事实上,这样做通常非常有用)。就像在同一个函数调用中组合不同类型的实参一样,在顺序上有一些限制:

    • 仅限位置的参数放在前面,然后跟随一个斜杠“/”。
    • 普通参数在任何仅限位置参数之后。
    • 不定量位置参数在正常参数之后。
    • 只有关键字参数在不定量位置参数之后。
    • 不定量关键字参数总是排在最后。

    对于仅限位置参数和普通参数,任何必需的参数必须在任何可选参数之前定义。这意味着,如果你有一个可选的仅限位置参数,那么所有常规参数也必须是可选的。该规则不影响仅限关键字的参数。

    如果没有例子,这些规则可能会有点难以理解,所以来看几个示例:

    # 定义个带有所有参数形式的函数
    def func(a, b, c=7, *args, **kwargs):
    print('a, b, c:', a, b, c)
    print('args:', args)
    print('kwargs:', kwargs)
    
    func(1, 2, 3, 5, 7, 9, A='a', B='b')

    注意函数定义中参数的顺序。执行该程序会得到以下结果:

    a, b, c: 1 2 3
    args: (5, 7, 9)
    kwargs: {'A': 'a', 'B': 'b'}

    现在再来看一个只有关键字参数的例子:

    # 仅限观自在参数
    def allparams(a, /, b, c=42, *args, d=256, e, **kwargs):
    print('a, b, c:', a, b, c)
    print('d, e:', d, e)
    print('args:', args)
    print('kwargs:', kwargs)
    
    allparams(1, 2, 3, 4, 5, 6, e=7, f=9, g=10)

    注意,在函数声明中有仅限位置形参和仅限关键字形参:a仅限位置形参,而d和e仅限关键字形参。他们是在*args可变量位置参数之后,如果它们紧跟在单个*的后面,也会是一样的(在这种情况下,将没有任何可变位置参数)。运行程序会得到以下结果:

    a, b, c: 1 2 3
    d, e: 256 7
    args: (4, 5, 6)
    kwargs: {'f': 9, 'g': 10}

    另一件需要注意的事情是我们为可变量位置参数和关键字参数命名。你可以自由选择不同的名称,但请注意,args和kwargs是这些参数的常规名称,至少在一般情况下是这样。

    7.更多的签名示例

    为了简要回顾一下使用仅限位置和关键字说明符的函数签名,下面是一些进一步的示例。省略不定量位置和关键字参数,为简洁起见,我们只剩下以下语法:

    def xxxFuncName(positional_only_parameters, /,
     positional_or_keyword_parameters, *,
     keyword_only_parameters):
    # 函数体
    pass

    首先,我们有仅限位置的参数,然后是位置或关键字参数,最后是仅限关键字参数。

    其他一些有效签名如下:

    def xxxFuncName(p1, p2, /, p_or_kw, *, kw):
    def xxxFuncName(p1, p2=None, /, p_or_kw=None, *, kw):
    def xxxFuncName(p1, p2=None, /, *, kw):
    def xxxFuncName(p1, p2=None, /):
    def xxxFuncName(p1, p2, /, p_or_kw):
    def xxxFuncName(p1, p2, /):

    以上均为有效签名,下列为无效签名:

    def xxxFuncName(p1, p2=None, /, p_or_kw, *, kw):
    def xxxFuncName(p1=None, p2, /, p_or_kw=None, *, kw):
    def xxxFuncName(p1=None, p2, /):

    你可以在官方文档中阅读语法规范:

    https://docs.python.org/3/reference/compound_stmts.html#functiondefinitions

    提示:在这一点上,要很好的理解与掌握,一个有用的练习方法是实现上述示例签名中的任何一个,打印出这些参数的值,就像我们在前面的练习中所做的那样,并以不同的方式传递参数。

    8.避免陷阱!可变默认值

    要注意的一件事是,在Python中,默认值是在定义时创建的;因此,根据默认值的可变性,对同一函数的后续调用可能会有不同的行为。让我们看一个例子:

    # 带有可变默认值参数函数
    def func(a=[], b={}):
    print(a)
    print(b)
    print('#' * 12)
    a.append(len(a)) # 影响a的默认值
    b[len(a)] = len(a) # 影响b的默认值
    
    func()
    func()
    func()

    两个参数都有可变的默认值。这意味着,如果执行中影响了这些对象,任何修改都将停留在后续的函数调用中。看看你是否能理解这些调用的输出:

    []
    {}
    ############
    [0]
    {1: 1}
    ############
    [0, 1]
    {1: 1, 2: 2}
    ############

    是不是很搞事?虽然这种行为一开始看起来很奇怪,但它实际上是有意义的,而且非常方便——例如,当使用“记忆”技术时,就有了天生之才的傲娇。更有趣的是,在调用之间,我们引入了一个不使用默认值的函数,比如:

    # 中间调停者调用
    func()
    func(a=[1, 2, 3], b={'B': 1})
    func()

    运行代码输出内容如下所示:

    []
    {}
    ############
    [1, 2, 3]
    {'B': 1}
    ############
    [0]
    {1: 1}
    ############

    这个输出告诉我们,即使使用其他值调用函数,默认值也会被保留。我想到的一个问题是,如何每次都获得一个新的空值?惯例是这样的:

    # 无陷阱可变缺省默认值
    def func(a=None):
    if a is None:
    a = []
    # 干些使用a的工作 ...

    注意,通过使用前面的技术,如果调用函数时没有传递a,我们总是得到一个全新的空列表。

    本文小结

    本文详细介绍了函数的输入参数分类、示例和调用,都是围绕如下主题展开:

    位置或关键字参数:同时允许位置和关键字参数;

    可变位置参数:在元组中收集任意数量的位置参数;

    可变关键字参数:在字典中收集任意数量的关键字参数;

    仅限位置参数:只能作为位置参数传递;

    •仅限关键字参数:只能作为关键字参数传递。​

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 编程 Python
    相关文章 更多
    python删除一个列表里的重复元素的方法与代码示例
    python删除一个列表里的重复元素的方法与代码示例

    学习如何使用Python高效删除列表中的重复元素。本文提供5种常见方法的代码示例,涵盖保持顺序与不保持顺序的场景,适合初学者和进阶开发者参考。

    Python写接口的步骤及完整代码示例
    Python写接口的步骤及完整代码示例

    详细讲解使用Python编写Web接口的核心步骤与完整代码示例,涵盖环境准备、路由定义、数据校验、服务启动及调试测试方法。

    codex怎么读取word文档及docx文件操作教程
    codex怎么读取word文档及docx文件操作教程

    介绍如何利用编程工具读取和解析Word文档(docx格式),涵盖基础文本提取代码示例、结构化数据处理逻辑,以及处理复杂排版时的技术局限与替代方案。

    怎么在Python中调用C语言代码提升性能
    怎么在Python中调用C语言代码提升性能

    详细讲解在Python中调用C语言代码提升性能的完整实践指南,包含原理分析、编译步骤、ctypes与CFFI具体实现、性能对比及常见陷阱。

    Python与C语言的性能差异及底层原理
    Python与C语言的性能差异及底层原理

    深入解析Python与C语言在执行效率上的数量级差异,从编译机制、变量内存布局、动态类型推断到GIL锁,系统阐明底层核心原理。

    Python和C语言哪个更适合编程入门
    Python和C语言哪个更适合编程入门

    客观对比Python与C语言在心智负担、底层机制与学习反馈上的核心差异,提供清晰有据的选择标准与切实的入门学习路径。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    langgraph python guide中文入门教程详解
    langgraph python guide中文入门教程详解

    本篇LangGraph Python中文入门教程详解,系统梳理StateGraph状态机定义、节点编写、边与条件路由、检查点持久化(MemorySaver)等核心机制,提供从环境安装到完整循环智能体构建的代码示例与实操指导。

    Windows 安装 Python:从官方入口到虚拟环境的可复现实践
    Windows 安装 Python:从官方入口到虚拟环境的可复现实践

    面向后端开发者,基于 Python 官方文档说明如何在 Windows 上安装 Python、创建 venv 虚拟环境及使用 pip 管理依赖。包含可复制命令、验证方法及工具选择边界,避免常见配置误区。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。