Python 检查参数是按位置传递还是通过关键字传递
考虑一个签名为f(a,b)的函数。将来,我想将签名更改为Python 检查参数是按位置传递还是通过关键字传递,python,python-3.x,Python,Python 3.x,考虑一个签名为f(a,b)的函数。将来,我想将签名更改为f(a,*,b),不允许将b作为位置参数传递。 为了减少更改的影响,我想首先反对按位置指定b,并警告这样做的用户 为此,我想写下如下内容: def f(a, b): frame = inspect.currentframe() if b in frame.specified_as_positional: print('Do not do that') else: print('Good
f(a,*,b)
,不允许将b作为位置参数传递。
为了减少更改的影响,我想首先反对按位置指定b,并警告这样做的用户
为此,我想写下如下内容:
def f(a, b):
frame = inspect.currentframe()
if b in frame.specified_as_positional:
print('Do not do that')
else:
print('Good')
结果是
>>> f(1, 2)
'Do not do that'
>>> f(1, b=2)
'Good'
inspect.getargvalues(frame)
似乎不够。ArgInfo对象只提供
>>> f(1,b=2)
ArgInfo(args=['a', 'b'], varargs=None, keywords=None, locals={'a': 1, 'b': 2})
这样的检查在Python中是否可行?从概念上讲,解释器似乎不需要记住参数是按位置指定的还是按关键字指定的
Python 2支持很好,但不是严格要求的。这里有一个非常黑客的解决方案:
def f(a, c=None, b=None):
if (b == None):
print("do not do that")
else:
print("good")
其中输入:
f(1,b=2)
printsgood
和f(1,2)
prints不要这样做
您可以使用包装器在用户和函数之间添加额外的步骤。在该步骤中,您可以在名称起作用之前检查参数。请注意,这取决于b
没有默认值,并且必须始终作为arg提供
functools.wrapps
用于使修饰后的函数在许多方面与原始函数相似
import functools
import warnings
def deprecate_positional(fun):
@functools.wraps(fun)
def wrapper(*args, **kwargs):
if 'b' not in kwargs:
warnings.warn(
'b will soon be keyword-only',
DeprecationWarning,
stacklevel=2
)
return fun(*args, **kwargs)
return wrapper
@deprecate_positional
def f(a, b):
return a + b
唯一想到的是
def(a,弃用的\u b=None,**kwargs):
-如果弃用的\u b
不是None,请给出警告,否则请查找kwargs['b']
。不建议这样做,但解析dis输出可能是一个选项,例如,{x.opname中的'CALL u FUNCTION\u KW in{x.opname for x.get\u指令('f(1,b=2)})
@jasonharper这是一个很好的建议。如果你把它作为答案发布,我很乐意接受。关于==None
:另外,如果b是None,使用而不是,如果c不是None
,不是更好吗?按照您的方式,您将无法区分是否有人故意使用b=None
@finefoot调用函数。我正在检查b,试图迫使用户为b传递一个值(而不是只传递一个参数)。我不认为传递的参数的值不能是None,但您是对的,它可以,这将导致我的实现中出现不需要的行为。(感谢您的链接!)您可能希望编辑您的答案以解决上述问题,因此我将删除我的评论。其他偶然发现这条线索的人将更容易通过这种方式。请参阅jasonharper对上述问题的评论以获取灵感。
>>> f(1, b=2)
3
>>> f(1, 2)
Warning (from warnings module):
File "C:/Users/nwerth/Desktop/deprecate_positional.py", line 36
print(f(1, 2))
DeprecationWarning: b will soon be keyword-only
3