Python 计算作为位置参数传递的参数数
如果我有一个函数Python 计算作为位置参数传递的参数数,python,function,parameter-passing,Python,Function,Parameter Passing,如果我有一个函数 def foo(x,y): 通过 如何从函数内部判断y是按位置传递还是随关键字传递 我想要点像这样的东西 def foo(x,y): 如果在位置上通过(y): 打印('y已按位置传递!') 其他: print('y与其关键字一起传递) 这样我就可以 foo(3,4) y在位置上通过 >>>foo(3,y=4) y与它的关键字一起传递 我意识到我最初并没有指定这一点,但在保留类型注释的同时是否可以这样做?到目前为止,最重要的答案是建议使用decorator-但是,这不会保
def foo(x,y):
通过
如何从函数内部判断y
是按位置传递还是随关键字传递
我想要点像这样的东西
def foo(x,y):
如果在位置上通过(y):
打印('y已按位置传递!')
其他:
print('y与其关键字一起传递)
这样我就可以
foo(3,4)
y在位置上通过
>>>foo(3,y=4)
y与它的关键字一起传递
我意识到我最初并没有指定这一点,但在保留类型注释的同时是否可以这样做?到目前为止,最重要的答案是建议使用decorator-但是,这不会保留返回类型您可以欺骗用户并向函数添加另一个参数,如下所示:
def foo(x,y1=None,y=None):
if y1 is not None:
print('y was passed positionally!')
else:
print('y was passed with its keyword')
def checkargs(func):
def inner(*args, **kwargs):
if 'y' in kwargs:
print('y passed with its keyword!')
else:
print('y passed positionally.')
result = func(*args, **kwargs)
return result
return inner
>>> @checkargs
...: def foo(x, y):
...: return x + y
>>> foo(2, 3)
y passed positionally.
5
>>> foo(2, y=3)
y passed with its keyword!
5
def checkargs(param_to_check):
def inner(func):
def wrapper(*args, **kwargs):
if param_to_check in kwargs:
print('y passed with its keyword!')
else:
print('y passed positionally.')
result = func(*args, **kwargs)
return result
return wrapper
return inner
>>> @checkargs(param_to_check='y')
...: def foo(x, y):
...: return x + y
>>> foo(2, y=3)
y passed with its keyword!
5
def foo(x, y):
if passed_positionally(y):
raise Exception("You need to pass 'y' as a keyword argument")
else:
process(x, y)
我不建议这样做,但它确实有效您可以创建一个装饰器,如下所示:
def foo(x,y1=None,y=None):
if y1 is not None:
print('y was passed positionally!')
else:
print('y was passed with its keyword')
def checkargs(func):
def inner(*args, **kwargs):
if 'y' in kwargs:
print('y passed with its keyword!')
else:
print('y passed positionally.')
result = func(*args, **kwargs)
return result
return inner
>>> @checkargs
...: def foo(x, y):
...: return x + y
>>> foo(2, 3)
y passed positionally.
5
>>> foo(2, y=3)
y passed with its keyword!
5
def checkargs(param_to_check):
def inner(func):
def wrapper(*args, **kwargs):
if param_to_check in kwargs:
print('y passed with its keyword!')
else:
print('y passed positionally.')
result = func(*args, **kwargs)
return result
return wrapper
return inner
>>> @checkargs(param_to_check='y')
...: def foo(x, y):
...: return x + y
>>> foo(2, y=3)
y passed with its keyword!
5
def foo(x, y):
if passed_positionally(y):
raise Exception("You need to pass 'y' as a keyword argument")
else:
process(x, y)
当然,您可以通过允许decorator接受参数来改进这一点。因此,您可以传递要检查的参数。可能是这样的:
def foo(x,y1=None,y=None):
if y1 is not None:
print('y was passed positionally!')
else:
print('y was passed with its keyword')
def checkargs(func):
def inner(*args, **kwargs):
if 'y' in kwargs:
print('y passed with its keyword!')
else:
print('y passed positionally.')
result = func(*args, **kwargs)
return result
return inner
>>> @checkargs
...: def foo(x, y):
...: return x + y
>>> foo(2, 3)
y passed positionally.
5
>>> foo(2, y=3)
y passed with its keyword!
5
def checkargs(param_to_check):
def inner(func):
def wrapper(*args, **kwargs):
if param_to_check in kwargs:
print('y passed with its keyword!')
else:
print('y passed positionally.')
result = func(*args, **kwargs)
return result
return wrapper
return inner
>>> @checkargs(param_to_check='y')
...: def foo(x, y):
...: return x + y
>>> foo(2, y=3)
y passed with its keyword!
5
def foo(x, y):
if passed_positionally(y):
raise Exception("You need to pass 'y' as a keyword argument")
else:
process(x, y)
我认为添加将保留注释,以下版本还允许对所有参数执行检查(使用):
从functools导入包装
进口检验
def checkargs(函数):
@包装(func)
def内部(*args,**kwargs):
对于inspect.signature(func.parameters)中的参数:
如果参数为kwargs:
打印(参数'passed with its keyword!')
其他:
打印(参数“按位置传递”)
结果=函数(*args,**kwargs)
返回结果
返回内部
>>>@checkargs
…:def foo(x,y,z)->int:
…:返回x+y
>>>foo(2,3,z=4)
x按位置通过。
他在位置上通过了。
z通过了它的关键字!
9
>>>inspect.getfullargspec(foo)
FullArgSpec(args=[],varargs='args',varkw='kwargs',默认值=None,
kwonlyargs=[],kwonlydefaults=None,annotations={'return':})
_____________这里____________
最后,如果要执行以下操作:
def foo(x,y1=None,y=None):
if y1 is not None:
print('y was passed positionally!')
else:
print('y was passed with its keyword')
def checkargs(func):
def inner(*args, **kwargs):
if 'y' in kwargs:
print('y passed with its keyword!')
else:
print('y passed positionally.')
result = func(*args, **kwargs)
return result
return inner
>>> @checkargs
...: def foo(x, y):
...: return x + y
>>> foo(2, 3)
y passed positionally.
5
>>> foo(2, y=3)
y passed with its keyword!
5
def checkargs(param_to_check):
def inner(func):
def wrapper(*args, **kwargs):
if param_to_check in kwargs:
print('y passed with its keyword!')
else:
print('y passed positionally.')
result = func(*args, **kwargs)
return result
return wrapper
return inner
>>> @checkargs(param_to_check='y')
...: def foo(x, y):
...: return x + y
>>> foo(2, y=3)
y passed with its keyword!
5
def foo(x, y):
if passed_positionally(y):
raise Exception("You need to pass 'y' as a keyword argument")
else:
process(x, y)
您可以这样做:
def foo(x, *, y):
pass
>>> foo(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes 1 positional argument but 2 were given
>>> foo(1, y=2) # works
def foo(x,*,y):
通过
>>>傅(1,2)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:foo()接受1个位置参数,但给出了2个
>>>foo(1,y=2)#工作
或者只允许按位置传递它们:
def foo(x, y, /):
pass
>>> foo(x=1, y=2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() got some positional-only arguments passed as keyword arguments: 'x, y'
>>> foo(1, 2) # works
定义foo(x,y,/):
通过
>>>foo(x=1,y=2)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:foo()获得了一些仅用于位置的参数,这些参数作为关键字参数传递:“x,y”
>>>富(1,2)#作品
有关更多信息,请参见和。通常不可能。从某种意义上说:这种语言不是为了让你区分两种方式而设计的 您可以将函数设计为采用不同的参数(位置参数、命名参数),并检查传递了哪一个参数,如下所示:
def foo(x, y=None, /, **kwargs):
if y is None:
y = kwargs.pop(y)
received_as_positional = False
else:
received_as_positional = True
问题是,尽管使用仅位置参数作为abov,您可以通过两种方式获得y
,
用户(或IDE)检查系统时不会显示一次
函数签名
我有一种感觉,你只是想知道这一点,为了知道-如果
你真的打算把它用于API的设计,我建议你重新考虑一下
您的API-在行为上应该没有区别,除非两者都有
从用户的角度来看,这些参数有明显的不同
也就是说,方法是检查调用者帧,然后检查
函数调用位置周围的字节码:
In[24]:导入系统,dis
在[25]中:def foo(x,y=None):
…:f=sys.\u getframe().f\u back
…:打印(dis.dis(f.f_代码))
...:
In[26]:foo(1,2)
1 0加载\u名称0(foo)
2负载常数0(1)
4负载常数1(2)
6调用函数2
8打印输出
10负载常数2(无)
12返回值
没有一个
In[27]:foo(1,y=2)
1 0加载\u名称0(foo)
2负载常数0(1)
4负载常数1(2)
6荷载常数2(‘y’,))
8呼叫功能2
10打印输出
12负载常数3(无)
14返回值
因此,如您所见,当调用
y
作为命名参数时,调用的操作码是call\u FUNCTION\u KW
,参数的名称立即加载到堆栈中。在foo
中,您可以将调用堆栈从回溯位置传递到,然后将解析这些行,找到调用foo
本身的行,然后使用ast
解析该行以定位位置参数规范(如果有):
输出:
y was passed with its keyword
注:
此解决方案不需要对foo
进行任何包装。只需要捕获回溯
要在回溯中以字符串形式获取完整的foo
调用,此解决方案必须在文件中运行,而不是在shell中运行
根据@cytorak的答案改编,这里有一种方法可以保持以下类型:
输入import-TypeVar、Callable、Any、TYPE\u检查
T=TypeVar(“T”,bound=Callable[…,Any])
从functools导入包装
进口检验
def checkargs()->可调用[[T],T]:
def装饰(func):
@包装(func)
def内部(*args,**kwargs):
对于inspect.signature(func.parameters)中的参数:
如果参数为kwargs:
打印(参数'passed with its keyword!')
其他:
打印(参数“按位置传递”)
结果=函数(*args,**kwargs)
返回结果
返回内部
返修
@checkargs()
def foo(x,y)->int:
返回x+y
如果类型_检查:
露缝_型(foo(2,3))
傅(2,3)
傅(2,,