获取关键字参数实际上传递给Python方法

Doc*_*r J 23 python arguments keyword

我梦想着一个带有显式关键字args的Python方法:

def func(a=None, b=None, c=None):
    for arg, val in magic_arg_dict.items():   # Where do I get the magic?
        print '%s: %s' % (arg, val)
Run Code Online (Sandbox Code Playgroud)

我想得到一个字典,只有调用者实际传入方法的那些参数,就像**kwargs,但我不希望调用者能够传递任何旧的随机args,不像**kwargs.

>>> func(b=2)
b: 2
>>> func(a=3, c=5)
a: 3
c: 5
Run Code Online (Sandbox Code Playgroud)

所以:有这样的咒语吗?在我的情况下,我碰巧能够将每个参数与其默认值进行比较以找到不同的参数,但是当你有九个参数时,这有点不雅并且变得单调乏味.对于奖励积分,提供一个咒语,即使调用者传递了一个分配了默认值的关键字参数,也可以告诉我:

>>> func(a=None)
a: None
Run Code Online (Sandbox Code Playgroud)

调皮!

编辑:(词法)函数签名必须保持不变.它是公共API的一部分,显式关键字args的主要价值在于它们的文档值.只是为了让事情变得有趣.:)

Doc*_*r J 25

我受到了失去理论的装饰者善良的启发,在玩了一下之后想出了一点:

def actual_kwargs():
    """
    Decorator that provides the wrapped function with an attribute 'actual_kwargs'
    containing just those keyword arguments actually passed in to the function.
    """
    def decorator(function):
        def inner(*args, **kwargs):
            inner.actual_kwargs = kwargs
            return function(*args, **kwargs)
        return inner
    return decorator


if __name__ == "__main__":

    @actual_kwargs()
    def func(msg, a=None, b=False, c='', d=0):
        print msg
        for arg, val in sorted(func.actual_kwargs.iteritems()):
            print '  %s: %s' % (arg, val)

    func("I'm only passing a", a='a')
    func("Here's b and c", b=True, c='c')
    func("All defaults", a=None, b=False, c='', d=0)
    func("Nothin'")
    try:
        func("Invalid kwarg", e="bogon")
    except TypeError, err:
        print 'Invalid kwarg\n  %s' % err
Run Code Online (Sandbox Code Playgroud)

打印这个:

I'm only passing a
  a: a
Here's b and c
  b: True
  c: c
All defaults
  a: None
  b: False
  c: 
  d: 0
Nothin'
Invalid kwarg
  func() got an unexpected keyword argument 'e'

我很高兴.更灵活的方法是将要使用的属性的名称传递给装饰器,而不是将其硬编码为"actual_kwargs",但这是解释该解决方案的最简单方法.

嗯,Python很好吃.


Alv*_*Row 16

这是最简单,最简单的方法:

def func(a=None, b=None, c=None):
    args = locals().copy()
    print args

func(2, "egg")
Run Code Online (Sandbox Code Playgroud)

这给出了输出:{'a': 2, 'c': None, 'b': 'egg'}.原因args应该是locals字典的副本是字典是可变的,所以如果你在这个函数中创建任何局部变量args将包含所有局部变量及其值,而不仅仅是参数.

在内置多个文档locals的功能在这里.

  • 很好 - 并且关闭 - 但是c不应该在那里.它没告诉我你传了哪些. (3认同)

Ale*_*lli 5

一种可能性:

def f(**kw):
  acceptable_names = set('a', 'b', 'c')
  if not (set(kw) <= acceptable_names):
    raise WhateverYouWantException(whatever)
  ...proceed...
Run Code Online (Sandbox Code Playgroud)

IOW,很容易检查传入的名称是否在可接受的集合内,否则会引发你想要Python引发的任何内容(TypeError,我猜;-).很容易变成装饰,顺便说一下.

另一种可能性

_sentinel = object():
def f(a=_sentinel, b=_sentinel, c=_sentinel):
   ...proceed with checks `is _sentinel`...
Run Code Online (Sandbox Code Playgroud)

通过创建一个唯一的对象,_sentinel您可以消除调用者可能意外传递的风险None(或调用者可能传递的其他非唯一默认值).这一切object()都是有益的,顺便说一句:一个极其轻量级,独特的哨兵,不可能与任何其他物体意外混淆(当你与is操作员核实时).

对于稍微不同的问题,任何一种解决方