得到kwargs Inside Function

Mar*_*ark 23 python introspection kwargs

如果我有这样的python函数:

def some_func(arg1, arg2, arg3=1, arg4=2):
Run Code Online (Sandbox Code Playgroud)

有没有办法确定哪些参数是通过关键字从函数内部传递的?

编辑

对于那些问我为什么需要这个的人,我没有真正的理由,它出现在一次谈话中,好奇心让我变得更好.

Ale*_*lli 19

不,没有办法在具有此签名的Python代码中执行此操作 - 如果您需要此信息,则需要更改函数的签名.

如果你看一下Python C API,你会发现参数传递给普通Python函数的实际方式总是作为一个元组加一个dict - 即直接反映签名的方式*args, **kwargs.然后将该元组和字典解析为特定的位置args和在签名中命名的那些,即使它们是通过名称传递的,*a并且**kw,如果存在,则仅从该解析中获取"溢出"(如果有的话) - 仅在这一点是你的Python代码得到控制,到那时你要求的信息(如何通过各种args)不再是.

因此,为了获得您所要求的信息,请将签名更改为*a, **kw并进行自己的解析/验证 - 这是"从鸡蛋到煎蛋",即一定量的工作但当然可行,而您正在寻找因为将"从煎蛋卷回鸡蛋"......根本不可行;-).


awe*_*omo 12

这是我通过装饰器的解决方案:

def showargs(function):
    def inner(*args, **kwargs):
        return function((args, kwargs), *args, **kwargs)
    return inner

@showargs
def some_func(info, arg1, arg2, arg3=1, arg4=2):
    print arg1,arg2,arg3,arg4
    return info

In [226]: some_func(1,2,3, arg4=4)
1 2 3 4
Out[226]: ((1, 2, 3), {'arg4': 4})
Run Code Online (Sandbox Code Playgroud)

可能有一种方法可以进一步清理它,但这似乎对我的干扰最小,并且不需要更改调用代码.

编辑:要实际测试是否通过关键字传递了特定的args,然后在some_func中执行以下操作:

args, kwargs = info
if 'arg4' in kwargs:
    print "arg4 passed as keyword argument"
Run Code Online (Sandbox Code Playgroud)

免责声明:你应该考虑一下你是否真的关心如何传递论据.整个方法可能是不必要的.


pyl*_*ang 7

有没有办法确定哪些参数是从函数内部通过关键字传递的?

在尝试评估关键字参数的默认值时,是的,有一些选项:

代码

选项1 -locals()

def f(a, b=1, c="1"):
    print(locals())


f(0)
# {'c': '1', 'b': 1, 'a': 0}
Run Code Online (Sandbox Code Playgroud)

选项 2 - 部分类型提示*

def g(a, b:int=1, c:str="1"):
    pass


keys = g.__annotations__
values = g.__defaults__

dict(zip(keys, values))
# {'b': 1, 'c': '1'}
Run Code Online (Sandbox Code Playgroud)

选项 3 - 完整类型提示*

def h(a:float, b:int=1, c:str="1") -> int:
    return 0


keys = reversed(list(filter(lambda x: x != "return", h.__annotations__)))
values = reversed(h.__defaults__)

{k: v for k, v in zip(keys, values) if k != "return"}
# {'c': '1', 'b': 1}
Run Code Online (Sandbox Code Playgroud)

注意:这些选项都不是特别 Pythonic,但它们展示了潜力。


细节

  1. locals()取决于函数调用。结果应该是默认值,但它们会随着传递到调用中的值而变化,例如f(0)与。f(0 2, 3)
  2. “部分”类型提示意味着仅注释关键字参数。添加任何其他注释将不适用于这种幼稚的方法。
  3. “完整”或完整类型提示可以包括其他参数。由于"return"注释是可选的,因此我们从键中过滤它。此外,我们向后迭代以修剪潜在的位置参数zip()

*这些选项取决于类型提示和键插入顺序保留 (Python 3.6+)。它们只给出默认值,不会随函数调用值而改变。目前,类型提示在 Python 中是可选的,因此在生产代码中应谨慎使用。


建议

我只会使用后一种方法来调试或快速检查函数的签名。事实上,给定仅关键字参数(右侧*),可以使用它inspect.getargspec()来捕获kwonlydefaults字典。

def i(a, *, b=1, c="1"):
    pass


spec = inspect.getfullargspec(i)
spec
# FullArgSpec(args=['a'], varargs=None, varkw=None, 
#             defaults=None, kwonlyargs=['b', 'c'], 
#             kwonlydefaults={'b': 1, 'c': '1'}, annotations={})

spec.kwonlydefaults
# {'b': 1, 'c': '1'}
Run Code Online (Sandbox Code Playgroud)

否则,将提到的一些技术与 的argsdefaults属性结合起来FullArgSpec

def get_keywords(func):
    """Return a dict of (reversed) keyword arguments from a function."""
    spec = inspect.getfullargspec(func)
    keys = reversed(spec.args)
    values = reversed(spec.defaults)
    return {k: v for k, v in zip(keys, values)}


get_keywords(f)
# {'c': '1', 'b': 1}
Run Code Online (Sandbox Code Playgroud)

其中FullArgSpec常规函数f将显示:

spec = inspect.getfullargspec(f)
spec
# FullArgSpec(args=['a', 'b', 'c'], varargs=None, varkw=None, 
#             defaults=(1, '1'), kwonlyargs=[], 
#             kwonlydefaults=None, annotations={})
Run Code Online (Sandbox Code Playgroud)