Python cambiar por nombre de clase?

Actualmente estoy haciendo esto, para hacer diferentes cosas basadas en el tipo de un objeto:

actions = { SomeClass: lambda: obj.name AnotherClass: lambda: self.normalize(obj.identifier) ...[5 more of these]... } for a in actions.keys(): if isinstance(obj, a): return actions[a]() 

¿Es posible cortar el bucle for y hacer algo como esto?

 actions[something to do with obj]() 

 class SomeClass( object ): .... def action( self ): return self.name class AnotherClass( object ): .... def action( self ): return self.normalize( self.identifier ) [5 more classes like the above two] a.action() 

Mas simple Mas claro Más extensible. Menos magia Sin diccionario Sin bucle

 actions[obj.__class__]() 

funciona si obj es realmente una instancia de (por ejemplo) SomeClass y no de una subclase, por lo que si ese es el caso, el resultado será diferente de su forma actual de manejarlo. También tenga en cuenta que esto podría generar un KeyError si la clase no tiene una acción correspondiente. Para manejar este caso de la misma manera que lo hace ahora (es decir, no hacer nada), puede usar

 actions.get(obj.__class__, lambda: None) 

para tener un valor predeterminado devuelto.

Ah, y escucha el comentario de S.Lott sobre tu pregunta. En muchos casos, hay mejores maneras de lograr algo como esto. Por ejemplo, podría hacer que todas sus clases definan un do_whatever(self) y simplemente llamen obj.do_whatever() .

Supongo que tienes una clase principal para todos esos, o al menos una mezcla. Ponga una función de retorno predeterminada en la matriz o mixin, y luego anule en aquellos que son diferentes … Es la única forma correcta de hacerlo.

Claro, crea código adicional, pero al menos es encapsulado y escalable. Digamos que quieres agregar soporte para cinco clases más. En lugar de alterar ese código allí arriba, simplemente agregue el código correcto a las nuevas clases. Por su aspecto, son dos líneas por clase (definición de función y línea de retorno). Eso no es malo, ¿verdad?

Si obj no es una clase que contiene una función de retorno, entonces se genera una excepción, que puede capturar e ignorar con una conciencia limpia.

 class MyMixin: def my_return(self, *args): return self.name ... possibly other things... class SomeClass(MyMixin): ... no alteration to the default ... class AnotherClass(MyParent, MyMixin): def my_return(self, *args): return args[0].normalize(self.identifier) ... blabla # now, this is in the caller object... try: rval = obj.my_return(self) # this is the caller object 'self', not the 'self' in the 'obj' #dosomething with rval except Exception: pass #no rval for this object type, skipping it... 

Qué pasa

 actions[obj.__class__]() 
 actions[type(obj)]() 
 results = [func() for cls, func in actions.iteritems() if isinstance(obj, cls)] 

Habrá cero o más resultados, si su objeto es una isinstance de cero o más de las claves de clase.

Usar type(obj) como clave solo funcionará si su objeto es de ese tipo. Si está más abajo en el árbol de herencia, te lo perderás.