获取函数内的 kwargs
如果我有一个像这样的 python 函数:
def some_func(arg1, arg2, arg3=1, arg4=2):
有没有办法确定函数内部通过关键字传递哪些参数?
编辑
对于那些问我为什么需要这个的人,我没有真正的理由,它是在一次谈话中出现的,好奇心战胜了我。
If I have a python function like so:
def some_func(arg1, arg2, arg3=1, arg4=2):
Is there a way to determine which arguments were passed by keyword from inside the function?
EDIT
For those asking why I need this, I have no real reason, it came up in a conversation and curiosity got the better of me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
不,无法在具有此签名的 Python 代码中执行此操作 - 如果您需要此信息,则需要更改函数的签名。
如果您查看 Python C API,您会发现参数传递给普通 Python 函数的实际方式始终是元组加字典的形式——即,直接反映
签名的方式*args,**kwargs
。然后,该元组和字典被解析为特定的位置参数和在签名中命名的参数,即使它们是按名称传递的,以及*a
和**kw
,如果存在,则仅从该解析中获取“溢出”(如果有)——只有此时您的 Python 代码才能获得控制权,然后您所请求的信息(如何是各种参数通过)已经不存在了。因此,要获取您请求的信息,请将签名更改为
*a, **kw
并进行您自己的解析/验证——这就是“从鸡蛋到煎蛋卷”,即某个特定的工作量很大,但肯定可行,而您正在寻找的将是“从煎蛋卷回到鸡蛋”......根本不可行;-)。No, there is no way to do it in Python code with this signature -- if you need this information, you need to change the function's signature.
If you look at the Python C API, you'll see that the actual way arguments are passed to a normal Python function is always as a tuple plus a dict -- i.e., the way that's a direct reflection of a signature of
*args, **kwargs
. That tuple and dict are then parsed into specific positional args and ones that are named in the signature even though they were passed by name, and the*a
and**kw
, if present, only take the "overflow" from that parsing, if any -- only at this point does your Python code get control, and by then the information you're requesting (how were the various args passed) is not around any more.To get the information you requested, therefore, change the signature to
*a, **kw
and do your own parsing/validation -- this is going "from the egg to the omelette", i.e. a certain amount of work but certainly feasible, while what you're looking for would be going "from the omelette back to the egg"... simply not feasible;-).这是我通过装饰器的解决方案:
可能有一种方法可以进一步清理它,但这对我来说似乎干扰最小,并且不需要更改调用代码。
编辑:要实际测试特定参数是否通过关键字传递,请在 some_func 中执行类似以下操作:
免责声明:您可能应该考虑是否真正关心如何传递论点获得通过。整个方法可能是不必要的。
Here's my solution via decorators:
There may be a way to clean this up further, but this seems minimally intrusive to me and requires no change to the calling code.
Edit: To actually test if particular args were passed by keyword, then do something like the following inside of some_func:
Disclaimer: you should probably consider whether or not you really care how the arguments were passed. This whole approach may be unnecessary.
在尝试评估关键字参数的默认值时,是的,有以下选项:
代码
选项 1 -
locals()
选项 2 - 部分类型提示*
选项 3 - 完整类型提示*
注意:这些选项都不是特别 Pythonic,但它们展示了潜力。
详细信息
locals()
取决于函数调用。结果应该是默认值,但它们会随着传递到调用中的值而变化,例如f(0)
与f(0 2, 3)
"return"
注释是可选的,因此我们从键中过滤它。此外,我们使用 zip() 向后迭代以修剪潜在的位置参数。*这些选项取决于类型提示和键插入顺序保留 (Python 3.6+)。它们只给出默认值,不会随函数调用值而改变。目前,类型提示在 Python 中是可选的,因此在生产代码中应谨慎使用。
建议
我只会使用后一种方法来调试或快速检查函数的签名。事实上,给定仅关键字参数(
*
右侧),可以使用inspect.getargspec()
捕获kwonlydefaults
字典。否则,将提到的一些技术与
FullArgSpec
的args
和defaults
属性相结合:其中
FullArgSpec
来自常规函数f
将显示:In trying to assess default values of keyword parameters, yes there are options:
Code
Option 1 -
locals()
Option 2 - Partial Type Hints*
Option 3 - Full Type Hints*
Note: None of these options are particularly Pythonic, but they demonstrate potential.
Details
locals()
depends on the function call. The results should be default values, but they change with values passed into the call, e.g.f(0)
vs.f(0 2, 3)
"return"
annotation is optional, we filter it from our keys. Furthermore, we iterate backwards to trim potential positional parameters withzip()
.*These options depend on type hints and key insertion order preservation (Python 3.6+). They only give the default values and do not change with function call values. Type hints are optional right now in Python, and thus should be used with caution in production code.
Suggestion
I would only use the latter approaches to debug or quickly inspect a function's signature. In fact, given keyword-only arguments (right of the
*
), one can useinspect.getargspec()
to capture thekwonlydefaults
dict.Otherwise, combine some of the mentioned techniques with the
args
anddefaults
attributes ofFullArgSpec
:where the
FullArgSpec
from the regular functionf
would show:您几乎必须重新定义您的功能:
并自己进行编组。无法区分按位置传递、按关键字传递和默认值之间的区别。
You're pretty much going to have to redefine your function:
and do the marshaling yourself. There's no way to tell the difference between pass-by-position, pass-by-keyword, and default.
只需这样做:
这样您就可以看到何时设置了某些内容,并且您还可以使用更复杂的默认结构(例如列表),而不会遇到以下问题:
Just do it like this:
That way you can see when something was set, and you are also able to work with more complex default structures (like lists) without running into problems like these:
您想知道
arg3
是1
是因为它是从外部传递的还是因为它是默认值?不,据我所知,没有办法做到这一点。我怀疑主要原因是不需要这些知识。通常执行的操作如下:do you want to know whether
arg3
was1
because it was passed from outside or because it was a default value? No there is no way to do this as far as I'm aware. The main reason, I suspect, that there is no need for such knowledge. What typically is done is the following:带有
inspect.signature
的 _kwargs 装饰器 hacks@awesomo 解决方案的一个变体,它引入了一个“私有”
_kwargs
参数,并且也适用于默认的 kwargs:用法:
_kwargs decorator with
inspect.signature
hacksA variant of @awesomo's solution which introduces a "private"
_kwargs
parameter and also works with default kwargs:Usage: