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')
    
  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wuxianfeng023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值