Python中的函数定义中的斜杠/和星号*

示例

  • 看一段代码

     def say_hello(name,age=18):
         print(f'你好!我是{name},今年我{age}啦。')
     say_hello('老吴')
     say_hello(name='小钱')
     ​
     # 输出
     你好!我是老吴,今年我18啦。
     你好!我是小钱,今年我18啦。
  • 这个代码你学过python不可能不懂,name是形式参数,也叫位置参数,我们一样可以用参数名=的方式传递(关键字参数)

  • 再看一段代码:这是list列表的index方法的定义描述

     >>> help(list.index)
     Help on method_descriptor:
     ​
     index(self, value, start=0, stop=9223372036854775807, /)
         Return first index of value.
     ​
         Raises ValueError if the value is not present.
  • 我们跟上面一样做个简单的测试

     >>> list1=[2,3,4]
     >>> list1.index(2)
     0
     >>> list1.index(value=2)
     Traceback (most recent call last):
       File "<stdin>", line 1, in <module>
     TypeError: list.index() takes no keyword arguments
    • 提示说list.index没有关键字参数

  • 细心的同学应该发现了,两者的差异在于第二个函数index的定义最后有个/,这个在初学的时候我们一般不会怎么接触到。但其实非常有用。

  • 除了/,还有一个*号,也会出现在函数定义中(注意不是*args和**kwargs)

  • 比如list的sort方法

     >>> help(list.sort)
     Help on method_descriptor:
     ​
     sort(self, /, *, key=None, reverse=False)
         Sort the list in ascending order and return None.
     >>> list1=[3,2,4]
     >>> list1.sort(reverse=True)   # 关键字参数传递方式
     >>> list1
     [4, 3, 2]
     >>> list1.sort(None,reverse=True)    # 不能用位置参数
     Traceback (most recent call last):
       File "<stdin>", line 1, in <module>
     TypeError: sort() takes no positional arguments

斜杠/之前必须是位置参数

  • 这个特性是在python3.8中发布的,仅限位置形参。

     https://docs.python.org/zh-cn/3.8/whatsnew/3.8.html
  • 示例1: 对之前的say_hello函数加个/看看

     def say_hello(name,/,age=18):
         print(f'你好!我是{name},今年我{age}啦。')
     say_hello('老吴')
     say_hello(name='小钱')
     ​
     ​
     你好!我是老吴,今年我18啦。
     ---------------------------------------------------------------------------
     TypeError                                 Traceback (most recent call last)
     <ipython-input-11-e09734cd0de5> in <module>
           2     print(f'你好!我是{name},今年我{age}啦。')
           3 say_hello('老吴')
     ----> 4 say_hello(name='小钱')
     ​
     TypeError: say_hello() got some positional-only arguments passed as keyword arguments: 'name'
    • 非常清楚的提示了,say_hello函数给一个仅限位置参数name用了关键字传参的方式

  • 示例2:放到最后会怎样?

     def say_hello(name,age=18,/):
         print(f'你好!我是{name},今年我{age}啦。')
     say_hello('老吴',19)
     say_hello('小钱',age=19)
     # 输出如下
     你好!我是老吴,今年我19啦。
     ---------------------------------------------------------------------------
     TypeError                                 Traceback (most recent call last)
     <ipython-input-14-911127531c6c> in <module>
           2     print(f'你好!我是{name},今年我{age}啦。')
           3 say_hello('老吴',19)
     ----> 4 say_hello('小钱',age=19)
     ​
     TypeError: say_hello() got some positional-only arguments passed as keyword arguments: 'age'
    • 对于默认值参数age,一样的不能用关键字参数方式传递,只能用位置参数

  • 示例3:/放在中间,对于/后的是没有限制的,下面2个调用都ok的。

    def say_hello(name,/,age):
    print(f'你好!我是{name},今年我{age}啦。')
    say_hello('老吴',18)
    say_hello('小钱',age=18)
  • 比如len

    >>> help(len)
    Help on built-in function len in module builtins: len(obj, /)
    Return the number of items in a container.
    • 你从来不会这样调用,你都不知道有obj这个参数,但其实你应该明白它是有参数的。

      >>> len(obj='ab')
      Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      TypeError: len() takes no keyword arguments

星号*后面必须是关键字参数

  • 没有找到出处

  • 但有了/的基础,你看到这个要求就比较容易理解了。

  • 示例1:

    def say_hello(name,*,age):
    print(f'你好!我是{name},今年我{age}啦。')
    say_hello('小钱',age=18) # * 号后面是关键字参数
    say_hello(name='啊徐',age=18) # * 前面的你随便用什么方式都可以(如果没有/的话)
    say_hello('老吴',18) # 你不能用位置参数的方式来调用 # 输出
    你好!我是小钱,今年我18啦。
    你好!我是啊徐,今年我18啦。
    ---------------------------------------------------------------------------
    TypeError Traceback (most recent call last)
    <ipython-input-21-2a30cd8f06c0> in <module>
    3 say_hello('小钱',age=18)
    4 say_hello(name='啊徐',age=18)
    ----> 5 say_hello('老吴',18) TypeError: say_hello() takes 1 positional argument but 2 were given

混合

  • 官方的定义:https://peps.python.org/pep-0570/

    def func(positional_only_parameters, /, positional_or_keyword_parameters,
    *, keyword_only_parameters):
    pass
  • 混合后有些定义跟普通的函数定义方式略有调整。

    # 对的
    def func1(p1, p2, /, p_or_kw, *, kw):
    pass
    def func2(p1, p2=None, /, p_or_kw=None, *, kw):
    pass
    def func3(p1, p2=None, /, *, kw): # 这个可能是最容易 让人误判的
    pass
    def func4(p1, p2=None, /):
    pass
    def func5(p1, p2, /, p_or_kw):
    pass
    def func6(p1, p2, /):
    pass
    def func7(p_or_kw, *, kw):
    pass
    def func8(*, kw):
    pass
  • 以上都是合法的,以下就是不合法的

    # 错的
    def fun9(p1, p2=None, /, p_or_kw, *, kw): # 错在 p_or_kw
    pass
    def fun10(p1=None, p2, /, p_or_kw=None, *, kw): # 错在 p1和 p2,
    pass
    def fun11(p1=None, p2, /):
    pass

好处?用途?

  • 这么做的好处是啥呢?

  • 将形参标记为仅限位置形参将允许在未来修改形参名而不会破坏客户的代码。

  • 示例1

    def say_hello(name,/,age=18):
    print(f'你好!我是{name},今年我{age}啦。') say_hello('wu',18) #通常你会这样调用
    # 以后,你觉得name不合适,改为xingming
    def say_hello(xingming,/,age=18):
    print(f'你好!我是{xingming},今年我{age}啦。') say_hello('wu',18) # 你的调用仍然可以正常工作

  • 示例2:来看一个函数定义

    def foo(name, **kwds):
    print(f'My name is : {name} ')
    return 'name' in kwds foo('wuxianfeng',name='zhangsan') # 本意是输出用户名,看看是否提供关键字参数name
    TypeError                                 Traceback (most recent call last)
    <ipython-input-33-07a88704ecfd> in <module>
    4
    5
    ----> 6 foo('wuxianfeng',name='zhangsan') TypeError: foo() got multiple values for argument 'name'
  • 这样改下即可。此name非彼name,name好像可以使用两次

    def foo(name, /,**kwds):
    print(f'My name is : {name} ')
    return 'name' in kwds foo('wuxianfeng',name='zhangsan')
  •  

Python中的函数定义中的斜杠/和星号*的更多相关文章

  1. [Python]Python Class 中的 函数定义中的 self

    In [80]: class MyClass001: ....: def selfDemo(self): ....: print 'My Demo' ....: In [81]: p = MyClas ...

  2. python开发_python中的函数定义

    下面是我做的几个用列: #python中的函数定义,使用和传参 def_str = '''\ python中的函数以如下形式声明: def 函数名称([参数1,参数2,参数3......]): 执行语 ...

  3. python 可变参数函数定义* args和**kwargs的用法

    python函数可变参数 (Variable Argument) 的方法:使用*args和**kwargs语法.其中,*args是可变的positional arguments列表,**kwargs是 ...

  4. python学习7—函数定义、参数、递归、作用域、匿名函数以及函数式编程

    python学习7—函数定义.参数.递归.作用域.匿名函数以及函数式编程 1. 函数定义 def test(x) # discription y = 2 * x return y 返回一个值,则返回原 ...

  5. 第7.23节 Python使用property函数定义属性简化属性访问的代码实现

    第7.23节 Python使用property函数定义属性简化属性访问的代码实现 一.    背景       在本章前面章节中,我们介绍了类相关的知识,并举例进行了说明,在这些例子中会定义一些形如 ...

  6. Python使用property函数定义的属性名与其他实例变量重名会怎么样?

    首先如果定义的属性名与该属性对应的操作方法操作的实例对象同名就会触发无穷的递归调用,相关部分请参考<Python案例详解:使用property函数定义与实例变量同名的属性会怎样?> 但如果 ...

  7. Python使用property函数定义属性访问方法如果不定义fget会怎么样?

    我们知道Python使用property函数定义属性访问方法时的语法如下: 实例属性=property(fget=None, fset=None, fdel=None, doc=None) 而是要@p ...

  8. python简单的函数定义和用法实例

    python简单的函数定义和用法实例 这篇文章主要介绍了python简单的函数定义和用法,实例分析了Python自定义函数及其使用方法,具有一定参考借鉴价值,需要的朋友可以参考下 具体分析如下: 这里 ...

  9. python中的函数(定义、多个返回值、默认参数、参数组)

    函数定义 在python中函数的定义以及调用如下代码所示: def test(x): y = x+1 return y result = test(2) print(result) 多个返回值的情况 ...

  10. python的函数定义中99%的人会遇到的一个坑

    列表是一种经常使用的数据类型.在函数的定义中,常常会使用列表作为参数. 比如,要测试一个接口的数据,接口返回的数据格式如下: { "code": "20000" ...

随机推荐

  1. Linux操作系统,笔录!

    1.Linux 1.1.Linux介绍: Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX ...

  2. 发布 .NET 7 MAUI / MAUI Blazor 应用到 Windows 应用商店

    .NET MAUI 目前仅允许发布 MSIX 包. 创建签名证书发布到本地传送门 [https://www.cnblogs.com/densen2014/p/16567384.html] 使用 Vis ...

  3. RocketMQ 在同程旅行的落地实践

    本文作者:刘树东 - 同程艺龙技术专家 01/使用概况 同程旅行选择RocketMQ主要基于以下几个方面的考虑: 技术栈:公司主要以 Java 开发为主,因此我们倾向于选择一款用 Java 实现的MQ ...

  4. 我的Python基础(二)

    python包含6种内奸的序列:列表.元组.字符串.Unicode字符串.buffer对象和xrange对象 列表和元组的主要区别在于,列表可以修改,元组则不能. 索引: 使用负数索引时,最后一个元素 ...

  5. 【Devexpres】spreadsheetControl自动列宽

    Worksheet worksheet = this.spreadsheetControl1.ActiveWorksheet; worksheet.Import(datatable, true, 0, ...

  6. 前端学习 linux —— 软件安装(Ubuntu)

    软件安装(Ubuntu) 本篇主要讲解 ubuntu 中软件的安装.apt 的源.内网部署案例(graylog 为例),最后是 python 开发准备. apt 和 rpm 在linux 第一篇我们知 ...

  7. Selenium4+Python3系列(九) - 上传文件及滚动条操作

    一.上传文件操作 上传文件是每个做自动化测试同学都会遇到,而且可以说是面试必考的问题,标准控件我们一般用send_keys()就能完成上传, 但是我们的测试网站的上传控件一般为自己封装的,用传统的上传 ...

  8. 关于linux mint新增加的鼠标样式的示例图片不能正确显示的解决办法

    前言 我相信你在linux mint 做鼠标主题美化的时候一定遇到过这样的问题 没错!!! 下载的鼠标的主题的示例图片不能正确显示,当然这样虽然不影响正常的鼠标主题更换使用,但是对于我这种强迫症来说简 ...

  9. 基于.net C# Socket WinForm MQTT 客户端开发

    1.什么是MQTT? MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的&quo ...

  10. 长度最小子数组-LeetCode209 滑动窗口

    力扣:https://leetcode.cn/problems/minimum-size-subarray-sum/ 题目 给定一个含有 n 个正整数的数组和一个正整数 target .找出该数组中满 ...