示例
-
看一段代码
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')