¿Puedes usar una cadena para crear una instancia de una clase?

Estoy usando un patrón de constructor para separar un montón de diferentes posibilidades de configuración. Básicamente, tengo un montón de clases que se denominan ID (algo como ID12345). Todos estos heredan de la clase de constructor base. En mi script, necesito crear una instancia para cada clase (aproximadamente 50) cada vez que se ejecuta esta aplicación. Entonces, estoy tratando de ver si en lugar de hacer algo como esto:

ProcessDirector = ProcessDirector() ID12345 = ID12345() ID01234 = ID01234() ProcessDirector.construct(ID12345) ProcessDirector.construct(ID01234) ID12345.run() ID01234.run() 

¿Puedo hacer algo como esto (sé que esto no funciona):

 IDS = ["ID12345", "ID01234"] ProcessDirector = ProcessDirector() for id in IDS: builder = id() #some how instantiate class from string ProcessDirector.construct(builder) builder.run() 

De esa manera, cuando necesito agregar una nueva en el futuro, todo lo que tengo que hacer es agregar la ID a la lista de IDS, en lugar de agregar la nueva ID en todo el código.

EDITAR

Parece que hay algunas opiniones diferentes basadas en el origen de los datos. Estas identificaciones se ingresan en un archivo al que nadie más tiene acceso. No estoy leyendo las cadenas desde la línea de comandos, y me gustaría poder hacer tan poca alteración al agregar una nueva ID en el futuro.

    No estoy seguro de que esto sea lo que quieres, pero parece una forma más Pythonic de instanciar un grupo de clases enumeradas en una cadena:

     class idClasses: class ID12345:pass class ID01234:pass # could also be: import idClasses class ProcessDirector: def __init__(self): self.allClasses = [] def construct(self, builderName): targetClass = getattr(idClasses, builderName) instance = targetClass() self.allClasses.append(instance) IDS = ["ID12345", "ID01234"] director = ProcessDirector() for id in IDS: director.construct(id) print director.allClasses # [<__main__.ID12345 instance at 0x7d850>, <__main__.ID01234 instance at 0x7d918>] 

    Si quisieras evitar una eval (), podrías simplemente hacer:

     id = "1234asdf" constructor = globals()[id] instance = constructor() 

    Siempre que la clase esté definida (o importada) en su ámbito actual.

    Nunca uses eval() si puedes evitarlo. Python tiene tantas opciones mejores (diccionario de despacho, getattr() , etc.) que nunca deberías usar el agujero de seguridad conocido como eval() .

    La forma más simple es simplemente crear un dict.

     class A(object): pass class B(object): pass namedclass = {'ID12345': A, 'ID2': A, 'B': B, 'AnotherB': B, 'ID01234': B} 

    Entonces utilízalo (tu ejemplo de código):

     IDS = ["ID12345", "ID01234"] ProcessDirector = ProcessDirector() for id in IDS: builder = namedclass[id]() ProcessDirector.construct(builder) builder.run() 

    Decidí armar la respuesta aceptada y un comentario sobre la respuesta aceptada. También agregué el __getitem__ sobrecargado para que se parezca más a un patrón de fábrica.

     import sys import traceback import ipdb class CarTypes: class Toyota: def __repr__(self): return "Toyota()" def __str__(self): return "Instance of Toyota() class" class Nissan: def __repr__(self): return "Nissan()" def __str__(self): return "Instance of Nissan() class" class Car: def __init__(self): self._all_classes = {} def construct(self, builder_name): setattr(self, builder_name, CarTypes()) try: target_class = getattr(CarTypes, builder_name) instance = target_class() self._all_classes[builder_name] = instance except AttributeError: print("Builder {} not defined.".format(builder_name)) traceback.print_stack() def __getitem__(self, type_name): return self._all_classes[type_name] def car_type(self, type_name): return self._all_classes[type_name] IDS = ["Toyota", "Nissan", "Unknown"] director = Car() for id in IDS: director.construct(id) print(director["Toyota"]) print(director["Nissan"]) print(director.car_type("Toyota")) print(director.car_type("Nissan")) 

    Editado : Agregué en algún manejo de errores.

    Editado : Colocado bajo licencia permisiva de Creative Commons . Disfrutar.

    Faltan algunas cosas en tu pregunta, así que me veo obligado a adivinar las cosas omitidas. Siéntase libre de editar su pregunta para corregir las omisiones.

     class ProcessDirector( object ): # does something class ID12345( SomeKindOfProcess ): pass class ID001234( SomeKindOfProcess ): pass idList= [ID12345, ID01234] theProcessDirector = ProcessDirector() for id in idList: builder = id() #Instantiate an object from the class object theProcessDirector.construct(builder) builder.run() 

    Esto funciona muy bien. No se crea una instancia de una cadena; en la práctica, a menudo no quieres esto. A veces, pero rara vez. Más comúnmente, usted es una lista de objetos de clase de los que desea objetos de instancia.

    Si realmente está obteniendo sus nombres de clase desde la línea de comando, entonces haría el siguiente pequeño cambio.

     validClasses = [ ID12345, ID01234 ] validMap = dict( ( (c.__name__, c) for c in validClasses ) ) nameStrings = [ "ID12345", "ID01234" ] # from your command-line idList= [ validMap[s] for s in nameStrings ] 

    Todo lo demás se mantiene igual.

    [Además, si es posible, intente iniciar nombres de variables de instancia con letras minúsculas. Los nombres que comienzan con letras mayúsculas suelen ser nombres de clase.]

    Editar

    Se ha eliminado eval . A pesar del hecho de que eval() es absolutamente un agujero de seguridad. Eval (y exec y execfile ) son solo un problema si alguien otorga específicamente acceso a usuarios malintencionados.