我如何强制某些功能参数仅在位置上

编程入门 行业动态 更新时间:2024-10-26 13:18:56
本文介绍了我如何强制某些功能参数仅在位置上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我想在Python3.7中模仿Python3.8的这种行为

I want to mimic this behaviour of Python3.8 in Python3.7

仅限位置参数 /是用来表示某些功能参数必须在位置上指定且不能用作关键字参数的语法.

Positional-only parameters / was the syntax introduced to indicate that some function parameters must be specified positionally and cannot be used as keyword arguments.

#Python3.8 def f(a,b,/,**kwargs): print(a,b,kwargs) >>> f(1,2,**{'a':100,'b':200,'c':300}) # 1 2 {'a': 100, 'b': 200, 'c': 300}

a,b仅用作位置参数.

我如何在Python3.7中做同样的事情

How I do the same in Python3.7

#Python3.7 def f(a,b,**kwargs): print(a,b,kwargs) >>> f(1,2,**{'a':1,'b':2}) # TypeError: f() got multiple values for argument 'a'

如何使a,b只是位置参数. /在下面的Python3.8中不起作用

How do I make a,b to be only positional parameters. / doesn't work below from Python3.8

是否可以在Python3.7中模仿/语法?

Is it possible to mimic / syntax in Python3.7?

推荐答案

您可以创建一个自定义装饰器,该装饰器声明仅位置参数,并返回一个包装器,该包装器解析其自己的*args, **kwargs,使它们适合装饰器的签名.功能.由于仅位置参数和关键字参数之间可能发生名称冲突,因此无法将关键字参数打包(**)用于此方法(这是唯一的限制).打包的关键字参数需要声明为最后的position-or-keyword参数或第一个仅关键字的参数.这是两个示例:

You can create a custom decorator that declares the positional-only arguments, returning a wrapper that parses its own *args, **kwargs such that they fit the signature of the decorated function. Due to possible name clashes between positional-only and keyword arguments, it is not possible to use keyword-argument-packing (**) for this approach (this is the only limitation). Packed keyword arguments need to be declared either as the last positional-or-keyword parameter or as the first keyword-only parameter. Here are two examples:

def foo(a, b, kwargs): # last positional-or-keyword parameter pass def foo(a, *args, kwargs): # first keyword-only parameter pass

变量kwargs将从包装器函数接收其余的**kwargs,即可以像在装饰函数中直接使用**kwargs一样使用它(类似于Python 3.8 +).

The variable kwargs will receive the remaining **kwargs from the wrapper function, i.e. it can be used similarly as if **kwargs had been used in the decorated function directly (like in Python 3.8+).

装饰器的以下实现很大程度上基于 inspect.Signature.bind 进行了一些小的调整,以通过装饰器声明的名称处理仅位置参数,并处理其他(人工)kwargs参数.

The following implementation of the decorator is largely based on the implementation of inspect.Signature.bind with a few minor tweaks to handle positional-only parameters via the decorator-declared names and to handle the additional (artificial) kwargs parameter.

import functools import inspect import itertools def positional_only(*names, kwargs_name='kwargs'): def decorator(func): signature = inspect.signature(func) @functools.wraps(func) def wrapper(*args, **kwargs): new_args = [] new_kwargs = {} parameters = iter(signature.parameters.values()) parameters_ex = () arg_vals = iter(args) while True: try: arg_val = next(arg_vals) except StopIteration: try: param = next(parameters) except StopIteration: break else: if param.name == kwargs_name or param.kind == inspect.Parameter.VAR_POSITIONAL: break elif param.name in kwargs: if param.name in names: msg = '{arg!r} parameter is positional only, but was passed as a keyword' msg = msg.format(arg=param.name) raise TypeError(msg) from None parameters_ex = (param,) break elif param.default is not inspect.Parameter.empty: parameters_ex = (param,) break else: msg = 'missing a required argument: {arg!r}' msg = msg.format(arg=param.name) raise TypeError(msg) from None else: try: param = next(parameters) except StopIteration: raise TypeError('too many positional arguments') from None else: if param.name == kwargs_name or param.kind == inspect.Parameter.KEYWORD_ONLY: raise TypeError('too many positional arguments') from None if param.kind == inspect.Parameter.VAR_POSITIONAL: new_args.append(arg_val) new_args.extend(arg_vals) break if param.name in kwargs and param.name not in names: raise TypeError( 'multiple values for argument {arg!r}'.format( arg=param.name)) from None new_args.append(arg_val) for param in itertools.chain(parameters_ex, parameters): if param.name == kwargs_name or param.kind == inspect.Parameter.VAR_POSITIONAL: continue try: arg_val = kwargs.pop(param.name) except KeyError: if (param.kind != inspect.Parameter.VAR_POSITIONAL and param.default is inspect.Parameter.empty): raise TypeError( 'missing a required argument: {arg!r}'.format( arg=param.name)) from None else: if param.name in names: raise TypeError( '{arg!r} parameter is positional only, ' 'but was passed as a keyword'.format(arg=param.name)) new_kwargs[param.name] = arg_val new_kwargs.update(kwargs=kwargs) return func(*new_args, **new_kwargs) return wrapper return decorator

以下是如何使用它的示例:

Here is an example of how it can be used:

@positional_only('a') def foo(a, *args, kwargs, b=9, c): print(a, args, b, c, kwargs) foo(1, **dict(a=2), c=3) # ok foo(1, 2, 3, 4, 5, c=6) # ok foo(1, b=2, **dict(a=3), c=4) # ok foo(a=1, c=2) # error foo(c=1) # error

更多推荐

我如何强制某些功能参数仅在位置上

本文发布于:2023-07-15 01:59:59,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1108364.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:位置   参数   功能

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!