Python 3.8 支持只接受位置参数了
2021 4 17 06:09 PM 449次查看
functools.cache
的源码时发现参数列表有个诡异的 /
:def cache(user_function, /):
'Simple lightweight unbounded cache. Sometimes called "memoize".'
return lru_cache(maxsize=None)(user_function)
翻了下文档才发现这个叫 Positional-Only Parameters。作用就是这个参数之前的参数都是位置参数,不能用参数名来传递,例如:
>>> def a(x, /, y):
... return x + y
...
>>> a(1, 2)
3
>>> a(1, y=2)
3
>>> a(x=1, y=2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: a() got some positional-only arguments passed as keyword arguments: 'x'
>>> a(1, **{'y': 2})
3
而如果只允许用参数名来传递的话(Keyword-Only Arguments),可以用
*
来分隔:>>> def b(x, /, y, *, z):
... return x + y + z
...
>>> b(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: b() takes 2 positional arguments but 3 were given
>>> b(1, 2, z=3)
6
>>> b(1, y=2, z=3)
6
>>> b(1, 2, **{'z': 3})
6
>>> b(1, **{'z': 3}, y=2)
6
这个语法的主要作用是这些位置参数会占用参数名,导致后续的参数没法使用这些参数名了,但这些参数名有时候又是不可控的。
常见的现象就是写装饰器时经常会带上
*args
和 **kwargs
以便接收任意参数,但如果还有一些自定义的参数,就可能和 kwargs
冲突了:>>> def c(x, **kwargs):
... print(x, kwargs)
...
>>> c(1)
1 {}
>>> c(1, **{'y': 1})
1 {'y': 1}
>>> c(1, **{'x': 1})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: c() got multiple values for argument 'x'
关键是这种现象还没法避免,你不知道其他地方会怎么调用这个函数,为了避免冲突经常会把参数名加个下划线,但现在可以把位置参数分隔开了,也就不会冲突了:>>> def d(x, /, **kwargs):
... print(x, kwargs)
...
>>> d(1, x=2)
1 {'x': 2}
>>> d(1, **{'x': 2})
1 {'x': 2}
至于 Keyword-Only Arguments,我认为用途主要是为了可读性,当一个函数的参数很多,或是有
bool
类型的参数时,用位置参数对于阅读代码的人来说可能完全看不懂,例如:>>> def fetch(url, timeout, retry):
... ...
...
>>> fetch('http://127.0.0.1', 1, False)
>>> def fetch(*, url, timeout, retry):
... ...
...
>>> fetch('http://127.0.0.1', 1, False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fetch() takes 0 positional arguments but 3 were given
>>> fetch(url='http://127.0.0.1', timeout=1, retry=False)
0条评论 你不来一发么↓