Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 计算作为位置参数传递的参数数_Python_Function_Parameter Passing - Fatal编程技术网

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,,