2010-10-20 10 views
5

Soy relativamente nuevo en Python y me gustaría saber si estoy reinventando una rueda o haciendo cosas de una forma no pitónica: leer mal.Declaración basada en el diccionario en forma de interruptor con acciones

Estoy reescribiendo algunos analizadores escritos originalmente en Lua. Hay una función que acepta un nombre de campo de la tabla importada y su valor, realiza algunas acciones sobre el valor y lo almacena en el diccionario de destino con un nombre de clave apropiado.

En el código original se resuelve mediante una declaración larga tipo conmutador con funciones anónimas como acciones. código Python tiene el siguiente aspecto:

class TransformTable: 
    target_dict = {} 
    ... 
    def mapfield(self, fieldname, value): 
     try: 
      { 
       'productid': self.fn_prodid, 
       'name': self.fn_name, 
       'description': self.fn_desc, 
       ... 
      }[fieldname](value) 
     except KeyError: 
      sys.stderr.write('Unknown key !\n') 

    def fn_name(val): 
     validity_check(val) 
     target_dict['Product'] = val.strip().capitalize() 
    ... 

función de cada "campo-controlador" hace diferentes acciones y tiendas en diferentes claves en target_dict, por supuesto. Como Python no admite funciones anónimas con sentencias (¿o me perdí algo?), Las funciones deben escribirse por separado, lo que hace que el código sea menos legible e innecesariamente complicado.

Se aprecian todos los consejos sobre cómo hacer tales tareas de una manera más elegante y más pitonica.

Thx

David

+0

Es posible que también desee esforzarse para evitar reinventar la pregunta buscando aquí otras similares antes de publicar una. – martineau

Respuesta

0

Apliqué un enfoque similar a @Matti Virkkunen'a hace un tiempo en mi answer a una pregunta llamada "switch case in python doesn't work; need another pattern". También demuestra una forma relativamente fácil y elegante de manejar campos desconocidos. Transcrito a los términos en su ejemplo, se vería así:

class TransformTable: 
    target_dict = {} 

    def productid(self, value): 
     ... 
    def name(self, value): 
     validity_check(value) 
     self.target_dict['Product'] = value.strip().capitalize() 
    def description(self, value): 
     ... 

    def _default(self, value): 
     sys.stderr.write('Unknown key!\n') 

    def __call__(self, fieldname, value): 
     getattr(self, fieldname, self._default)(value) 

transformtable = TransformTable() # create callable instance 

transformtable(fieldname, value) # use it 
+1

Esa es una solución un poco más limpia. Gracias. ¿Qué tan bien funcionaría si los nombres de campo (extraídos de la tabla de importación) contendrán caracteres unicode (con diacrítico), es decir. definir funciones con nombres que no sean ascii? –

+0

Para usar el mecanismo que se muestra se necesita algún tipo de mapeo desde lo que se está encendiendo hasta el nombre del identificador válido. Por encima supone que es 1: 1. Otra forma más general de manejar esto sería tener un diccionario separado o una tabla de búsqueda que asigne cada entrada válida ('fieldname' aquí) a un nombre de método único, que podría ser simplemente' method1', 'method2', etc. Para cambiar en valores enteros, tiene algo así como '' case_ '+ str (number) '. El mapeo no necesita ser 1: 1, en el sentido de que varias entradas pueden ser manejadas por el mismo método, por ejemplo. Puedes personalizarlo como quieras. – martineau

+0

Thx para aclaración. Así que mi solución original con mapeo 1: 1 por diccionario en la sección de prueba estaba cerca de esto. –

1

Si por cualquier medio posible, usted podría nombrar sus funciones miembro basado en los nombres de campo y simplemente hacer algo como esto:

getattr(self, "fn_" + fieldname)(value) 

Editar: Y se puede use hasattr para verificar si la función existe, en lugar de esperar un KeyError. O espera un AttributeError. En cualquier caso, debe poner solo el acceso dentro de su try..except, y llamarlo afuera, ya que de lo contrario un KeyError causado dentro de uno de los métodos de campo podría malinterpretarse.

+0

Buenas ideas con generalización de nombres de funciones. –

+0

Buenas ideas con generalización de nombres de funciones. ¿Existe también una forma más general de diccionario -> correlaciones de diccionario (clave de clave con transformación de valor)? –

+0

Creo que esta es la forma estándar de activar cadenas en un contexto de clase. Soy demasiado perezoso para encontrar el enlace, pero sé que Guido se ha referido a él como una solución muy elegante. Es holandés así que el camino correcto es instantáneamente obvio para él. – aaronasterling

Cuestiones relacionadas