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. Sprint产品待办列表的优先级要怎么排?

    在梳理产品待办事项列表的过程中,产品负责人需要先做优先级排列,保证我们 在一定的时间盒内能够交付需要优先级最高.最具价值的用户故事. 那这个用户故事的优先级要怎么排列,我们怎样选择用户故事的实现顺序? ...

  2. VS Code插件推荐

    VS Code插件推荐 ​ VS Code作为前端开发人员在学习工作中必不可少的开发软件,其强大的功能以及丰富多样的插件都让开发人员爱不释手.下面推荐个人觉得还不错的几个插件,希望可以帮助到你.如果你 ...

  3. Emgu实现图像分割

    C#通过Emgu这个图像处理库,可以很方便的将一幅单通道图像分割为R.G.B三个单通道图像. Image<Bgr, Byte> ImageBGR = null; Image<Bgr, ...

  4. docker中php xdebug调试开发

    docker-compose环境来自:https://github.com/zhaojunlik...原文:http://blog.oeynet.com/post/9... 说明 在开发中,断点调试是 ...

  5. ArrayList 可以完全替代数组吗?

    本文已收录到  GitHub · AndroidFamily,有 Android 进阶知识体系,欢迎 Star.技术和职场问题,请关注公众号 [彭旭锐] 加入 Android 交流群. 前言 大家好, ...

  6. Froms

    首先看到的是一个输入框 不多说,直接bp抓下来 然后传repeater里,发现了pin值后showsource值,pin值没什么,应该是做题用的,而showsource是个隐藏的值,将其0改为1后go ...

  7. 关于咪咕视频的m3u8再次解析

    软件和源码 前言 之前写过一片文章: 关于突破咪咕视频付费限制的研究, 但是后来我发现评论说已经不能用了,我知道肯定是api修改了,写这种东西就是这样,不一定什么时候就变化了,然后就用不了了,我懒得继 ...

  8. 第2-4-6章 springboot整合规则引擎Drools-业务规则管理系统-组件化-中台

    目录 7. Spring整合Drools 7.1 Spring简单整合Drools 7.1.1 以上代码均在drools_spring项目中 7.2 Spring整合Drools+web 7.2 以上 ...

  9. day24 JDBC批处理(通用泛型查询方法 & 下划线转驼峰命名法)

    批处理 public static Integer addBatch(String[] sqls){ init(); try { //设置关闭自动提交 conn.setAutoCommit(false ...

  10. 【JVM调优】Day03:GC参数、OOM出现方式、调优实战

    一.常用GC参数(20个左右即可) 1.各种垃圾回收器的参数 PS + PO 常用的只有几十个 CMS的比较多,不建议使用 G1的常用参数简单 ZGC只有三个参数 二.OOM出现的方式 1.写一个让内 ...