En Python, ¿qué determina el orden mientras se repite en kwargs?

En Python, escribí esta función para enseñarme cómo funciona **kwargs en Python:

 def fxn(a1, **kwargs): print a1 for k in kwargs: print k, " : ", kwargs[k] 

Entonces llamé a esta función con

 fxn(3, a2=2, a3=3, a4=4) 

Aquí estaba la salida que mi intérprete de Python imprimió:

 3 a3 : 3 a2 : 2 a4 : 4 

¿Por qué el bucle for imprimió el valor de a3 antes que a2, aunque primero introduje a2 en mi función?

    kwargs es un diccionario. Los diccionarios no están ordenados; en pocas palabras, el orden no está especificado y es un detalle de la implementación. Mirar debajo del capó mostrará que el orden varía enormemente según los valores de hash de los elementos, el orden de inserción, etc., por lo que es mejor que no confíe en nada relacionado con él.

    Este es un diccionario. Y, como se menciona en la documentación, el diccionario no tiene orden (de http://docs.python.org/tutorial/datastructures.html#dictionaries ):

    Es mejor pensar en un diccionario como un conjunto desordenado de pares clave: valor , con el requisito de que las claves sean únicas (dentro de un diccionario).

    Pero puedes hacerlo procesado en algún orden , así:

    • utilizando sorted() :

       def fxn(a1, **kwargs): print a1 for k in sorted(kwargs): # notice "kwargs" replaced by "sorted(kwargs)" print k, " : ", kwargs[k] 
    • o utilizando el tipo OrderedDict (puede pasar el objeto OrderedDict como parámetro que contiene todos los pares clave-valor):

       from collections import OrderedDict def fxn(a1, ordkwargs): print a1 for k in ordkwargs: print k, " : ", ordkwargs[k] fxn(3, OrderedDict((('a2',2), ('a3',3), ('a4',4)))) 

    La desafortunada ironía es que la dictadura de ** kwargs significa que lo siguiente no funcionará (al menos no de la manera que uno esperaría):

     od = OrderedDict(a=1, b=2, c=3) 

    Dado que los argumentos con palabras clave se construyen primero en un dict desordenado, no puede depender de que se insertarán en el OrderedDict en el orden en que aparecen. 🙁

    Finalmente, esto se introdujo en la versión 3.6 : los dict ahora están ordenados, por lo que se conserva el orden de los argumentos de palabras clave.

     Python 3.6.0 (default, Jan 13 2017, 13:27:48) >>> def print_args(**kwargs): ... print(kwargs.keys()) ... >>> print_args(first=1, second=2, third=3) dict_keys(['first', 'second', 'third']) 

    Dado que kwargs es un diccionario de Python, que se implementa como una tabla hash , su orden no se conserva y es efectivamente aleatorio.

    En realidad, como solución a un problema de seguridad reciente en muchos lenguajes de progtwigción, en el futuro, el orden puede incluso cambiar entre las invocaciones de su progtwig (invocaciones del intérprete de Python).

    kwargs es un diccionario, en Python no están ordenados, por lo que el resultado es esencialmente (pseudo) aleatorio.