Гарантирован ли порядок словаря Python в течение итераций? - PullRequest
32 голосов
/ 13 января 2010

В настоящее время я реализую сложную микробную пищевую сеть в Python, используя SciPy.integrate.ode . Мне нужна способность легко добавлять виды и реакции в систему, поэтому я должен написать нечто общее. Моя схема выглядит примерно так:

class Reaction(object):
    def __init__(self):
        #stuff common to all reactions
    def __getReactionRate(self, **kwargs):
        raise NotImplementedError

... Reaction subclasses that 
... implement specific types of reactions


class Species(object):
    def __init__(self, reactionsDict):
        self.reactionsDict = reactionsDict
        #reactionsDict looks like {'ReactionName':reactionObject, ...}
        #stuff common to all species

    def sumOverAllReactionsForThisSpecies(self, **kwargs):
        #loop over all the reactions and return the 
        #cumulative change in the concentrations of all solutes

...Species subclasses where for each species
... are defined and passed to the superclass constructor

class FermentationChamber(object):
    def __init__(self, speciesList, timeToSolve, *args):
        #do initialization

    def step(self):
        #loop over each species, which in turn loops 
        #over each reaction inside it and return a 
        #cumulative dictionary of total change for each 
        #solute in the whole system


if __name__==__main__:
    f = FermentationChamber(...)

    o  = ode(...) #initialize ode solver

    while o.successful() and o.t<timeToSolve:
         o.integrate()

    #process o.t and o.y (o.t contains the time points
    #and o.y contains the solution matrix)

Итак, вопрос в том, когда я перебираю словари в Species.sumOverAllReactionsForThisSpecies() и FermentationChamber.step(), является ли порядок итераций словарей гарантированно одинаковым, если между словарями между первым и первым не будет добавлено или удалено ни одного элемента последняя итерация? То есть можно ли предположить, что порядок массива numpy, создаваемого на каждой итерации из словаря, не будет меняться? Например, если словарь имеет формат {'Glucose': 10, 'Fructose': 12}, если массив, созданный из этого словаря, будет всегда иметь тот же порядок (не имеет значения, что это порядок, пока он детерминирован).

Извините за мегапост, я просто хотел сообщить вам, откуда я.

Ответы [ 5 ]

59 голосов
/ 13 января 2010

Да, тот же порядок гарантирован, если он не изменен.

См. Документы здесь .

Edit:

Если изменение значения (но не добавление / удаление ключа) повлияет на порядок, то это то, что говорится в комментариях в C-источнике:

/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
 * dictionary if it's merely replacing the value for an existing key.
 * This means that it's safe to loop over a dictionary with PyDict_Next()
 * and occasionally replace a value -- but you can't insert new keys or
 * remove them.
 */

Кажется, что это не деталь реализации, а требование языка.

8 голосов
/ 13 января 2010

При условии нет внесены изменения в словарь, ответ - да. Смотри документы здесь .

Однако в Python словари не упорядочены по своей природе. В общем случае не рекомендуется полагаться на словари для конфиденциальных отсортированных данных.

Примером более надежного решения будет Структура данных SortedDict Django .

7 голосов
/ 13 января 2010

Если вы хотите, чтобы заказ был последовательным, я бы сделал что-то для принудительного выполнения определенного заказа. Хотя вы можете убедить себя в том, что порядок гарантирован, и, возможно, вы правы, он кажется мне хрупким и загадочным для других разработчиков.

Например, вы подчеркиваете всегда в своем вопросе. Важно ли, чтобы это было в том же порядке в Python 2.5 и 2.6? 2.6 и 3.1? CPython и Jython? Я бы на них не рассчитывал.

6 голосов
/ 13 января 2010

Я бы также рекомендовал не полагаться на то, что порядок словарей неслучайный.

Если вы хотите встроенное решение для сортировки словаря, прочитайте http://www.python.org/dev/peps/pep-0265/

Вот наиболее актуальный материал:

Этот ПКП отклонен, потому что потребность в нем была в значительной степени выполняется встроенной функцией sorted () Py2.4:

    >>> sorted(d.iteritems(), key=itemgetter(1), reverse=True)
    [('b', 23), ('d', 17), ('c', 5), ('a', 2), ('e', 1)]

or for just the keys:

    >>> sorted(d, key=d.__getitem__, reverse=True)
    ['b', 'd', 'c', 'a', 'e']

Also, Python 2.5's heapq.nlargest() function addresses the common use
case of finding only a few of the highest valued items:

    >>> nlargest(2, d.iteritems(), itemgetter(1))
    [('b', 23), ('d', 17)]
3 голосов
/ 13 января 2010

Python 3.1 имеет collection.OrderedDict класс, который можно использовать для этой цели. Это также очень эффективно: «Время выполнения Big-O для всех методов такое же, как и для обычных словарей».

Код для OrderedDict сам по себе совместим с Python 2.x, хотя некоторые унаследованные методы (из модуля _abcoll ) используют функции только для Python 3. Однако их можно изменить на код 2.x с минимальными усилиями.

...