2011-10-22 6 views
6

Tengo una situación en la que tengo seis situaciones posibles que pueden relacionarse con cuatro resultados diferentes. En lugar de usar una instrucción if/else extendida, me preguntaba si sería más pitónico usar un diccionario para llamar a las funciones que llamaría dentro del if/else como reemplazo de una instrucción "switch", como una que podría usarse en C# o php.¿Es este un método "pythonic" de ejecución de funciones como una declaración de cambio de pitón para valores de tupla?

Mi declaración de cambio depende de dos valores que estoy usando para construir una tupla, que a su vez utilizaré como la clave del diccionario que funcionará como mi "interruptor". Obtendré los valores para la tupla de otras dos funciones (llamadas a bases de datos), por lo que tengo las funciones de ejemplo one() y zero().

Este es el patrón de código que estoy pensando en usar la que me topé con jugar en la cáscara de pitón:

def one(): 
    #Simulated database value 
    return 1 

def zero(): 
    return 0 

def run(): 
    #Shows the correct function ran 
    print "RUN" 
    return 1 

def walk(): 
    print "WALK" 
    return 1 

def main(): 
    switch_dictionary = {} 

    #These are the values that I will want to use to decide 
    #which functions to use 
    switch_dictionary[(0,0)] = run 
    switch_dictionary[(1,1)] = walk 

    #These are the tuples that I will build from the database 
    zero_tuple = (zero(), zero()) 
    one_tuple = (one(), one()) 

    #These actually run the functions. In practice I will simply 
    #have the one tuple which is dependent on the database information 
    #to run the function that I defined before 
    switch_dictionary[zero_tuple]() 
    switch_dictionary[one_tuple]() 

que no tienen el código real o escrito que iba a publicar aquí, como Me gustaría saber si este método se considera una mejor práctica de Python. Todavía soy un aprendiz de pitón en la universidad, y si este es un método que es un mal hábito, me gustaría patearlo ahora antes de salir al mundo real.

Nota: el resultado de ejecutar el código anterior es el esperado, simplemente "RUN" y "WALK".

edición

Para aquellos de ustedes que están interesados, así es como el código en cuestión resultó. Se está utilizando en una aplicación de motor de aplicación de Google. Debería encontrar que el código es considerablemente más ordenado que mi patrón de ejemplo aproximado. Funciona mucho mejor que mi anterior árbol intrincado if/else.

def GetAssignedAgent(self): 
    tPaypal = PaypalOrder() #Parent class for this function 
    tAgents = [] 
    Switch = {} 

    #These are the different methods for the actions to take 
    Switch[(0,0)] = tPaypal.AssignNoAgent 
    Switch[(0,1)] = tPaypal.UseBackupAgents 
    Switch[(0,2)] = tPaypal.UseBackupAgents 
    Switch[(1,0)] = tPaypal.UseFullAgents 
    Switch[(1,1)] = tPaypal.UseFullAndBackupAgents 
    Switch[(1,2)] = tPaypal.UseFullAndBackupAgents 
    Switch[(2,0)] = tPaypal.UseFullAgents 
    Switch[(2,1)] = tPaypal.UseFullAgents 
    Switch[(2,2)] = tPaypal.UseFullAgents 

    #I'm only interested in the number up to 2, which is why 
    #I can consider the Switch dictionary to be all options available. 
    #The "state" is the current status of the customer agent system 
    tCurrentState = (tPaypal.GetNumberofAvailableAgents(), 
        tPaypal.GetNumberofBackupAgents()) 

    tAgents = Switch[tCurrentState]() 
+0

Mucho mejor! Muy legible y 'Pythonic' – dawg

+0

Tenga en cuenta que 'Switch [(x, y)]' puede escribirse más limpiamente como 'Switch [x, y]' – Eric

Respuesta

11

consideran este idioma en su lugar:

>>> def run(): 
... print 'run' 
... 
>>> def walk(): 
... print 'walk' 
... 
>>> def talk(): 
... print 'talk' 
>>> switch={'run':run,'walk':walk,'talk':talk} 
>>> switch['run']() 
run 

Creo que es un poco más fácil de leer que la dirección se está desplazando.

edición

Y esto funciona así:

>>> switch={0:run,1:walk} 
>>> switch[0]() 
run 
>>> switch[max(0,1)]() 
walk 

puede incluso utilizar este lenguaje para una estructura switch/default Tipo:

>>> default_value=1 
>>> try: 
... switch[49]() 
... except KeyError: 
... switch[default_value]() 

O (al menos legible, más breve):

>>> switch[switch.get(49,default_value)]() 
walk 

edición 2

mismo idioma, extendido a su comentario:

>>> def get_t1(): 
... return 0 
... 
>>> def get_t2(): 
... return 1 
... 
>>> switch={(get_t1(),get_t2()):run} 
>>> switch 
{(0, 1): <function run at 0x100492d70>} 

legibilidad importa

+0

El problema es que construiré dinámicamente la tupla basada en llamadas a la base de datos como yo Ya estoy trabajando para devolver 0, 1 o 2 según los resultados de la base de datos en la función. Entonces usar tuplas vs cadenas simples es realmente muy necesario ya que necesito usar dos valores (potencialmente más en el futuro). Aunque me gusta mucho la idea de usar "cambiar" como el nombre del diccionario. –

+0

Es posible que desee considerar construido una clase simple, entonces. La cosa "pitonica" en general es recordar que la legibilidad importa mucho. Algo como 'switch_dictionary [(0,0)] = run' y' zero_tuple = (zero(), zero()) 'es difícil de descifrar para los demás (o usted mismo después de unos meses). Python tiene una tendencia a ser muy legible. Los modismos que eliges hacen la diferencia. Puede escribir este mismo código de una manera más legible. – dawg

+0

Mi problema particular es similar a un sistema de servicio al cliente, donde asigna solicitudes de clientes a dos tipos diferentes de agentes de servicio al cliente (cada mitad de la tupla en mi descripción), pero varía su comportamiento en función del número de cada tipo de agente en línea. La tupla será algo así como (GetTier1(), GetTier2()), por lo que posiblemente una tupla en este caso sea más legible? No estoy acostumbrado a que otros lean mi código python, así que estoy genuinamente interesado. –

2

Es una práctica pitón razonablemente común para despachar a funciones basadas en un diccionario o una secuencia buscar.

Teniendo en cuenta el uso de índices para la búsqueda, una lista de listas también funcionaría:

switch_list = [[run, None], [None, walk]] 
    ... 
switch_list[zero_tuple]() 

Lo que se considera más Pythonic es el que maximiza la claridad, mientras que el cumplimiento de otros requisitos operacionales. En su ejemplo, la tupla de búsqueda no parece tener un significado intrínseco, por lo que se pierde la intención operativa de una constante mágica. Intenta asegurarte de que la lógica comercial no se pierda en tu mecanismo de despacho. Usar nombres significativos para las constantes probablemente ayude.

Cuestiones relacionadas