2012-01-23 6 views
12

В Python, я написал эту функцию, чтобы научить меня, как **kwargs работает в Python:В Python, что определяет порядок при итерации через kwargs?

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

Я тогда назвал эту функцию с

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

Здесь был вывод, что мой переводчик Python напечатал:

3 
a3 : 3 
a2 : 2 
a4 : 4 

Почему цикл for печатает значение a3 перед значением a2, даже если я сначала подал a2 в свою функцию?

ответ

24

kwargs - это словарь. Словари неупорядочены - просто поставлены, порядок не определен и деталь реализации. Подглядывание под капотом покажет, что порядок сильно варьируется в зависимости от хеш-значений элементов, порядка вставки и т. Д., Поэтому вам лучше не полагаться на что-либо, связанное с ним.

1

kwargs - словарь, на Python они не упорядочены, поэтому результат по существу (псевдо) случайный.

10

Это словарь. И, как было сказано в документации, словарь не имеет никакого порядка (от http://docs.python.org/tutorial/datastructures.html#dictionaries):

Лучше думать о словаре как неупорядоченный набор пар ключ: значение, с требованием, чтобы ключи являются уникальными (в пределах одного словаря).

Но вы можете сделать это обрабатывается в определенном порядке, как это:

  • использованием sorted():

    def fxn(a1, **kwargs): 
        print a1 
        for k in sorted(kwargs): # notice "kwargs" replaced by "sorted(kwargs)" 
         print k, " : ", kwargs[k] 
    
  • или с помощью OrderedDict типа (вы можете передать OrderedDict объект как параметр, содержащий все пары ключ-значение):

    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)))) 
    
+0

Смотрите мой ответ в отношении OrderedDict – PaulMcG

+0

@PaulMcGuire:.. См. мой комментарий к вашему ответу. – Tadeck

+0

Не могли бы вы написать это как 'fxn (3, ** OrderedDict (и т. д.)?? О, подождите, я вижу, что вы изменили подпись, чтобы взять dict, а не набор аргументов ключевых слов Если вы собираетесь изменить подпись, тогда вы можете просто передать список ваших корневых ключей. Но OP действительно хотел перебрать ** kwargs. – PaulMcG

2

Поскольку kwargs является Python словарь, который реализуется как hash table, ее упорядочение не сохраняется и эффективно случайны.

На самом деле, как исправление к недавнему security issue во многих языках программирования, в будущем порядок может даже измениться между вызовами вашей программы (вызовы интерпретатора Python).

+2

Не случайно - на самом деле, это совершенно определенно. Просто не легко предсказуемо, так как это зависит от хэша. –

+1

Ты, конечно, прав. Именно по этой причине я сказал «эффективно случайный», чтобы указать читателю, что он не должен пытаться угадать. На боковой ноте почти все, что делает компьютер, является детерминированным, но может быть нелегко предсказуемым :) – spatz

4

Несчастный ирония заключается в том, что ДИКТ-кации из ** kwargs означает, что следующий не будет работать (по крайней мере, не так, как можно было бы ожидать):

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

Поскольку keyworded арг впервые встроены в неупорядоченный dict, вы не можете зависеть от того, что они будут вставлены в OrderedDict в том порядке, в котором они перечислены.:(

+1

Но следующее: 'od = OrderedDict ((('a', 1), ('b', 2), (' с», 3)))'. Таким образом, в основном '** kwargs', потому что это' dict', не будет никакого порядка, но вы всегда можете передать 'OrderedDict' как параметр, и у него будет тот порядок, который вы хотите получить. – Tadeck

3

Это, наконец, был введен в 3.6 release**kwargs теперь является OrderedDict, поэтому порядок аргумент ключевого слова сохраняется

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']) 
+0

'** kwargs' не являются' OrderedDict' в Python 3.6. Они по-прежнему являются «dict», но теперь «dict» упорядочен. –

Смежные вопросы