如何在 Python3 中将外部函数参数捆绑为'*args'?



假设我有以下函数:

class Foo:
@classmethod
def bar(cls, a, b): # do not want to use *args or **kwargs
return 'a b'

@classmethod
def advanced_bar(cls, a, b): # do not want to use *args or **kwargs
ab = cls.bar(a, b)
return ab.upper()

我的问题是:我如何以一种精简的,有点健壮的方式,将调用范围参数捕获为*args类型的对象,并将advanced_bar写为:

@classmethod
def bar(cls, a, b): # did not define any *args or *kwargs bins for arguments to overflow into
return 'a b'
@classmethod
def advanced_bar(cls, a, b):
...
x = 'y'  # added in a local variable

ab = cls.bar(*this_functions_args)
return ab.upper()

我添加了一些额外的东西,我认为这些东西会打破这个问题的最简单的解决方案。

特别地,我想避免多余的,冗长的噪音:

def advanced_bar(cls, a, b): # specifically defined args (I do not want to accept *args or **kwargs here)
args = (a,b)
ab = cls.bar(*args) # haven't really gained anything
return ab.upper()

因此,鉴于这个解决方案,我认为一个装饰器是一个足够的答案。


我在函数的入口点不使用*args**kwargs的原因是利用IDE。

我认为在函数签名中冗长是非常重要的,这是我的个人风格——我认为从接口中删除名字是错误的。

所以,我正在寻找一种方法,把我的蛋糕分成一半,然后吃掉它:似乎应该有这样一种方法。


拥有显式命名的函数参数,代码中没有*args**kwargs漏洞,根据需要预先定义尽可能多的局部变量,并拥有*args语法工具的一种方法可能是在内部以某种方式修饰函数…

# alternatively, I can use the idiom
def foo:
args = locals()

这是可能的,但这是一个坏主意,因为您依赖于CPython内部。假设您只想处理*args,而不是**kwargs:

import sys
def get_local_args():
calling_frame = sys._getframe().f_back
caller = calling_frame.f_code
relevant_vars = caller.co_varnames[:caller.co_argcount]
return [calling_frame.f_locals[name] for name in relevant_vars]
def foo(a, b):
if (a, b) == (1, 2):
return "a b"
return "c d"
def bar(a, b):
c = 23
assert foo(*get_local_args()) == "a b"
bar(1, 2)

传递所有函数参数(包括位置参数和命名参数)的标准习惯用法是:

@classmethod
def bar(cls, a, b): # did not define any *args or *kwargs bins for arguments to overflow into
return 'a b'
@classmethod
def advanced_bar(cls, *args, **kwargs):
...
x = 'y'  # added in a local variable

ab = cls.bar(*args, **kwargs)
return ab.upper()

如果不符合您的要求,请澄清您的问题。

如何在函数签名中使用*args并将其解构为函数体中的组件?

def something_else(a, b):
print(a, b)
def do_something(*args):
a, b = args
print('A', a)

something_else(*args)

编辑:

使用locals()的hack方式,基于https://stackoverflow.com/a/50763376/3080592

def do_something(a, b):
args = locals()
something_else(*args)

最新更新