10
votes

Mutabilité de l'argument ** kwargs en python

Considérez un cas où je modifie le kwargs dict à l'intérieur d'une méthode: xxx

si j'appelle la méthode pop_arg avec un dictionnaire comme ceci: xxx

va mydic être modifié par cet appel?

Je suis également intéressé par une explication plus détaillée de Le mécanisme d'appel de méthode sous-jacent qui permet mydict changer ou non.


0 commentaires

3 Réponses :


16
votes

Non, myDICT code> ne sera pas modifié. Les kwargs sont décompressés dans un nouveau dictionnaire.

Considérez le cas où vous avez: P>

def print_arg(key=1,**kwargs):
    print key
    print kwargs

print_arg(**{'key':2,'foo':3,'bar':4})


1 commentaires

Il convient de noter explicitement que ce sera une copie peu profonde cependant.



8
votes

La réponse de Mgilson est correcte. Mais vous devez également être conscient de la copie peu profonde.

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'}


0 commentaires

6
votes

Voyons:

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


0 commentaires