[英]Mutability of the **kwargs argument in Python
Consider a case where I change the kwargs
dict inside a method: 考虑一下我在方法内部更改
kwargs
dict的情况:
def print_arg(**kwargs):
print kwargs.pop('key')
If I call the method pop_arg
with a dictionary like this: 如果我用这样的字典调用方法
pop_arg
:
mydict = {'key':'value'}
print_arg(**mydict)
will mydict
be changed by this call? 这个电话会改变
mydict
吗?
I am also interested in a more detailed explanation of the underlying method calling mechanism that lets mydict
change or not. 我也对使
mydict
更改或不更改的基础方法调用机制的更详细说明感兴趣。
No, mydict
won't be changed. 不,
mydict
不会改变。 kwargs get unpacked into a new dictionary. 小矮人被打包成一本新字典。
Consider the case where you have: 考虑以下情况:
def print_arg(key=1,**kwargs):
print key
print kwargs
print_arg(**{'key':2,'foo':3,'bar':4})
In this case, it's obvious that kwargs is a different dict than you pass in because when it gets unpacked, it's missing the 'key'
key. 在这种情况下,很明显,kwargs是与您传入的字典不同的字典,因为当将其打开包装时,它会丢失
'key'
键。
@mgilson's answer is correct. @mgilson的答案是正确的。 But you should also be aware about the shallow copy.
但您也应该注意浅表副本。
def print_arg(**kwargs):
print kwargs.pop('key')
kwargs['list'].pop() # will affect the original
kwargs['dict'].pop('a') #will affect the original
mydict = {'key':'value', 'list':[2,3,4,5] ,'dict': { 'a':1,'b':2 }}
print_arg(**mydict)
print (mydict) # Output : {'dict': {'b': 2}, 'list': [2, 3, 4], 'key': 'value'}
Let's see: 让我们来看看:
import dis
dis.dis(lambda: print_arg(**{'key': 'value'}))
6 0 LOAD_GLOBAL 0 (print_arg)
3 BUILD_MAP 1
6 LOAD_CONST 1 ('value')
9 LOAD_CONST 2 ('key')
12 STORE_MAP
13 CALL_FUNCTION_KW 0
16 RETURN_VALUE
Let's find what CALL_FUNCTION_KW
does ( ceval.c
): 让我们找到
CALL_FUNCTION_KW
( ceval.c
)的作用:
case CALL_FUNCTION_VAR:
case CALL_FUNCTION_KW:
case CALL_FUNCTION_VAR_KW:
{
// ...
x = ext_do_call(func, &sp, flags, na, nk);
// ...
static PyObject *
ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
{
int nstar = 0;
PyObject *callargs = NULL;
PyObject *stararg = NULL;
PyObject *kwdict = NULL;
PyObject *result = NULL;
if (flags & CALL_FLAG_KW) { // if ** is involved
kwdict = EXT_POP(*pp_stack); // get the dict passed with **
if (!PyDict_Check(kwdict)) {
PyObject *d;
d = PyDict_New(); // make a NEW dict
if (d == NULL)
goto ext_call_fail;
if (PyDict_Update(d, kwdict) != 0) { // update it with old
// .. fail ..
goto ext_call_fail;
}
Py_DECREF(kwdict);
kwdict = d; // kwdict is now the new dict
}
}
....
result = PyObject_Call(func, callargs, kwdict); // call with new dict
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.