2010-01-12 8 views
21

Actualmente estoy implementando una compleja red alimentaria microbiana en Python usando SciPy.integrate.ode. Necesito la habilidad de agregar fácilmente especies y reacciones al sistema, así que tengo que codificar algo bastante general. Mi plan es como la siguiente:¿Está garantizado el orden de un diccionario de Python en las iteraciones?

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) 

Entonces, la pregunta es, cuando iterar sobre los diccionarios en Species.sumOverAllReactionsForThisSpecies() y FermentationChamber.step(), es el orden de iteración de los diccionarios garantizados a ser el mismo si se añaden o eliminan sin elementos de los diccionarios entre la primera y la última iteración? Es decir, ¿puedo suponer que el orden de la matriz numpy creada en cada iteración del diccionario no variará? Por ejemplo, si un diccionario tiene el formato {'Glucose': 10, 'Fructose': 12}, si un Array creado a partir de este diccionario tendrá siempre tendrá el mismo orden (no importa cuál sea ese orden, ya que siempre y cuando sea determinista).

Perdón por la mega publicación, solo quería que supiera de dónde vengo.

+0

@ChinmayKanchi ¿te importa si edito esta pregunta? Todos los detalles sobre las redes alimentarias y la integración de ODE no tienen nada que ver con la pregunta, que es muy buena e importante. – LondonRob

Respuesta

4

Python 3.1 tiene una clase collections.OrderedDict que se puede utilizar para este propósito. También es muy eficiente: "Los tiempos de ejecución de Big-O para todos los métodos son los mismos que para los diccionarios regulares".

El code for OrderedDict en sí mismo es compatible con Python 2.x, aunque algunos métodos heredados (del módulo _abcoll) sí usan las características de solo Python 3. Sin embargo, pueden modificarse al código 2.x con un mínimo esfuerzo.

+1

Esto realmente no responde la pregunta, y el uso de OrderedDict, aunque garantiza el orden determinista, aumentará el uso de recursos (sin embargo, no estoy seguro de qué manera exactamente). Como indican otras respuestas, un dict normal ya tiene esta garantía, por lo que no es necesario utilizar OrderedDict (para este caso de uso particular). –

43

Sí, el mismo pedido está garantizado si no se modifica.

Consulte los documentos here.

Editar:

En cuanto a si se cambia el valor (pero no añadir/eliminar una clave) afectará el orden, esto es lo que los comentarios en el C-fuente dice:

/* 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. 
*/ 

Parece que no es un detalle de implementación, sino un requisito del lenguaje.

+0

¡Ah, excelente! No estaba seguro de haber interpretado eso correctamente. Solo para estar seguro, no importa si los _valores_ sí mismos son modificados, ¿cierto, mientras las claves no lo sean? –

+2

Estoy bastante seguro de que "sin modificaciones" significa * no * modificaciones, punto. Cambiar los valores * puede * alterar el orden de clasificación del diccionario. –

+0

¡Maldición! Parece que tendré que replantear ese algoritmo. ¿Hay una estructura de datos ordenada tipo mapa en scipy/numpy o la biblioteca estándar de python? Preferiría no tener que depender de más bibliotecas de las que tengo que. –

8

Proporcionado no las modificaciones se hacen en el diccionario, la respuesta es sí. See the docs here.

Sin embargo, los diccionarios no están ordenados por naturaleza en Python. En general, no es la mejor práctica confiar en los diccionarios para datos clasificados confidenciales.

Un ejemplo de una solución más robusta sería Django's SortedDict data structure.

7

Si desea que el pedido sea coherente, haría algo para forzar un pedido en particular. Aunque es posible que pueda convencerse a sí mismo de que la orden está garantizada, y puede que tenga razón, me parece frágil y misteriosa para otros desarrolladores.

Por ejemplo, enfatice siempre en su pregunta. ¿Es importante que sea el mismo orden en Python 2.5 y 2.6? 2.6 y 3.1? CPython y Jython? No contaría con esos.

+0

¡Exactamente! La fragilidad de esto es lo que me impediría hacerlo ... –

+1

Buen punto. No estaba seguro de cuán frágil sería cuando formulé esta pregunta. Un replanteamiento de este algoritmo definitivamente está en orden. –

5

También recomendaría no confiar en el hecho de que el orden de los diccionarios no es aleatorio.

Si desea una solución integrada en la clasificación que el diccionario de leer http://www.python.org/dev/peps/pep-0265/

Aquí es el material más relevante:

Este PEP se rechaza porque la necesidad de que en gran medida ha sido cumplida por Py2.de 4 ordenados() función interna:

>>> 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)] 
Cuestiones relacionadas