python 在函数内部获取 kwargs
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2088056/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get kwargs Inside Function
提问by Mark
If I have a python function like so:
如果我有一个像这样的python函数:
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.
对于那些问我为什么需要这个的人,我没有真正的理由,它出现在一次谈话中,好奇心占了上风。
采纳答案by Alex Martelli
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.
不,没有办法用这个签名在 Python 代码中做到这一点——如果你需要这个信息,你需要更改函数的签名。
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 (howwere the various args passed) is not around any more.
如果您查看 Python C API,您会发现将参数传递给普通 Python 函数的实际方式始终是元组加上 dict —— 即,直接反映*args, **kwargs
. 然后将该元组和 dict 解析为特定的位置参数和签名中命名的参数,即使它们是按名称传递的,并且*a
and **kw
,如果存在,仅从该解析中获取“溢出”,如果有的话——仅在此时您的 Python 代码是否得到控制,到那时您请求的信息(各种参数是如何传递的)不再存在。
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;-).
因此,要获取您请求的信息,请将签名更改为*a, **kw
并进行您自己的解析/验证——这是“从鸡蛋到煎蛋”,即一定量的工作但肯定可行,而您正在寻找因为将“从煎蛋卷回到鸡蛋”......根本不可行;-)。
回答by awesomo
Here's my solution via decorators:
这是我通过装饰器的解决方案:
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})
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:
编辑:要实际测试特定参数是否通过关键字传递,请在 some_func 中执行以下操作:
args, kwargs = info
if 'arg4' in kwargs:
print "arg4 passed as keyword argument"
Disclaimer:you should probably consider whether or not you really care how the arguments were passed. This whole approach may be unnecessary.
免责声明:您可能应该考虑是否真的关心参数是如何传递的。这整个方法可能是不必要的。
回答by Mike DeSimone
You're pretty much going to have to redefine your function:
您几乎将不得不重新定义您的功能:
def some_func(*args, **kwargs):
and do the marshaling yourself. There's no way to tell the difference between pass-by-position, pass-by-keyword, and default.
并自己进行编组。无法区分位置传递、关键字传递和默认值之间的区别。
回答by pylang
Is there a way to determine which arguments were passed by keywordfrom inside the function?
有没有办法确定从函数内部通过关键字传递了哪些参数?
In trying to assess default values of keyword parameters, yes there are options:
在尝试评估关键字参数的默认值时,是的,有以下选项:
Code
代码
Option 1 - locals()
选项1 - locals()
def f(a, b=1, c="1"):
print(locals())
f(0)
# {'c': '1', 'b': 1, 'a': 0}
Option 2 - Partial Type Hints*
选项 2 - 部分类型提示*
def g(a, b:int=1, c:float="1"):
pass
keys = g.__annotations__
values = g.__defaults__
dict(zip(keys, values))
# {'b': 1, 'c': '1'}
Option 3 - Full Type Hints*
选项 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}
Note: None of these options are particularly Pythonic, but they demonstrate potential.
注意:这些选项都不是特别 Pythonic,但它们展示了潜力。
Details
细节
locals()
depends on the function call. The results should default values,, but they change with values passed into the call, e.g.f(0)
vs.f(0 2, 3)
- "Partial" type hints mean only keyword parameters are annotated. Adding any other annotations will not work with this naive approach.
- "Full" or complete type hints may include other parameters. We iterate backwards to avoid zipping values with optional positional parameters. Since a
"return"
annotation is optional, we filter it during iteration.
locals()
取决于函数调用。结果应该是默认值,但它们会随着传递到调用中的值而变化,例如f(0)
vs.f(0 2, 3)
- “部分”类型提示意味着只注释关键字参数。添加任何其他注释不适用于这种幼稚的方法。
- “完整”或完整类型提示可能包括其他参数。我们向后迭代以避免使用可选的位置参数压缩值。由于
"return"
注释是可选的,我们在迭代期间对其进行过滤。
*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.
*这些选项取决于类型提示和键插入顺序保留(Python 3.6+)。它们只给出默认值,不随函数调用值而改变。类型提示现在在 Python 中是可选的,因此在生产代码中应谨慎使用。
Suggestion
建议
I would only use the latter approaches to debug or quickly inspect a function's signature. In fact, given keyword-only arguments, one can use inspect.getargspec()
to capture the kwonlydefaults
dict.
我只会使用后一种方法来调试或快速检查函数的签名。事实上,给定关键字参数,可以inspect.getargspec()
用来捕获kwonlydefaults
字典。
def f(a, *, b=1, c="1"):
pass
spec = inspect.getfullargspec(f)
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'}
Otherwise, combine the some techniques with the args
and defaults
attributes of FullArgSpec
:
否则,将一些技术与 的args
和defaults
属性结合起来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}
回答by poke
Just do it like this:
只是这样做:
def some_func ( arg1, arg2, arg3=None, arg4=None ):
if arg3 is None:
arg3 = 1 # default value
if arg4 is None:
arg4 = 2 # default value
# do something
That way you can see when something was set, andyou are also able to work with more complex default structures (like lists) without running into problems like these:
这样,你可以看到,当一些设置,而且你还可以用更复杂的默认结构(如列表)的工作,而不会在像这样的问题:
>>> def test( arg=[] ):
arg.append( 1 )
print( arg )
>>> test()
[1]
>>> test()
[1, 1]
回答by SilentGhost
do you want to know whether arg3
was 1
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:
你想知道arg3
是1
因为它是从外部传递的还是因为它是一个默认值?不,据我所知,没有办法做到这一点。我怀疑,主要原因是不需要这些知识。通常执行的操作如下:
>>> def func(a, b=None):
if b is None:
# here we know that function was called as:
# func('spam') or func('spam', None) or func('spam', b=None) or func(a='spam', b=None)
b = 42