2011-01-27 14 views
101

En python, tengo que instanciar cierta clase, conociendo su nombre en una cadena, pero esta clase 'vive' en un módulo importado dinámicamente. Un ejemplo es el siguiente:instanciación dinámica de Python desde el nombre de cadena de una clase en el módulo importado dinámicamente

secuencia de comandos de clase loader:

import sys 
class loader: 
    def __init__(self, module_name, class_name): # both args are strings 
    try: 
     __import__(module_name) 
     modul = sys.modules[module_name] 
     instance = modul.class_name() # obviously this doesn't works, here is my main problem! 
    except ImportError: 
     # manage import error 

guión algunos de módulo cargado dinámicamente-:

class myName: 
    # etc... 

I utilizar esta disposición para hacer cualquier-módulo cargado dinámicamente para ser utilizado por la clase loader siguiendo ciertos comportamientos predefinidos en los módulos dyn-loaded-

Se agradecen todas las ideas.

Respuesta

149

Puede utilizar getattr

getattr(module, class_name) 

acceder a la clase. Código más completo:

module = __import__(module_name) 
class_ = getattr(module, class_name) 
instance = class_() 

Como se mencionó below, podemos utilizar importlib

import importlib 
module = importlib.import_module(module_name) 
class_ = getattr(module, class_name) 
instance = class_() 
+3

'module = __import __ (module, fromlist = [name])' solo funcionó para mí. – umpirsky

+15

Si alguien tiene problemas con el método de importación mencionado anteriormente, Sven encontré que mi código funcionaba mejor utilizando el siguiente método en su lugar [importlib.import_module] (http://docs.python.org/2/library/importlib.html#importlib .import_module). Puede ser utilizado como: module = importlib.import_module (module_name) – jpennell

+0

@jpennell debe publicar eso como respuesta, a menudo es más útil poder usar directamente la cadena devuelta por 'obj .__ module__' – Anentropic

11

Uso getattr para obtener un atributo de un nombre en una cadena. En otras palabras, obtener la instancia como fragmento

instance = getattr(modul, class_name)() 
9

Copiar y pegar:

def str_to_class(module_name, class_name) 
    try: 
     module_ = importlib.import_module(module_name) 
     try: 
      class_ = getattr(module_, class_name)() 
     except AttributeError: 
      logging.error('Class does not exist') 
    except ImportError: 
     logging.error('Module does not exist') 
    return class_ or None 
5

Si desea que esta frase from foo.bar import foo2 a ser cargado dinámicamente, usted debe hacer esto

foo = __import__("foo") 
bar = getattr(foo,"bar") 
foo2 = getattr(bar,"foo2") 

instance = foo2() 
2

I no pude llegar allí en mi caso de uso de los ejemplos anteriores, pero Ahmad me consiguió el más cercano (gracias). Para aquellos que lean esto en el futuro, aquí está el código que funcionó para mí.

def get_class(fully_qualified_path, module_name, class_name, *instantiation): 
    """ 
    Returns an instantiated class for the given string descriptors 
    :param fully_qualified_path: The path to the module eg("Utilities.Printer") 
    :param module_name: The module name eg("Printer") 
    :param class_name: The class name eg("ScreenPrinter") 
    :param instantiation: Any fields required to instantiate the class 
    :return: An instance of the class 
    """ 
    p = __import__(fully_qualified_path) 
    m = getattr(p, module_name) 
    c = getattr(m, class_name) 
    instance = c(*instantiation) 
    return instance 
84

tl; dr

Importe el módulo con importlib.import_module y cargar la clase que necesita con getattr:

# Standard import 
import importlib 
# Load "module.submodule.MyClass" 
MyClass = getattr(importlib.import_module("module.submodule"), "MyClass") 
# Instantiate the class (pass arguments to the constructor, if needed) 
instance = MyClass() 

explicaciones

Es probable que no desea utilizar __import__ a Importe dinámicamente un módulo por nombre, ya que no le permite importar submódulos:

>>> mod = __import__("os.path") 
>>> mod.join 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'module' object has no attribute 'join' 

Here es lo que el doc dice acerca de pitón __import__:

Note: This is an advanced function that is not needed in everyday Python programming, unlike importlib.import_module().

lugar, utilice el módulo estándar importlib importar dinámicamente un módulo por su nombre.Con getattr a continuación, puede crear una instancia de una clase por su nombre:

import importlib 
my_module = importlib.import_module("module.submodule") 
MyClass = getattr(my_module, "MyClass") 
instance = MyClass() 

También podría escribir:

import importlib 
module_name, class_name = "module.submodule.MyClass".rsplit(".", 1) 
MyClass = getattr(importlib.import_module(module_name), class_name) 
instance = MyClass() 

Este código es válido en Python ≥ 2.7 (incluyendo Python 3).

+0

tal vez no entiendo su respuesta, pero he usado __import__ para importar submódulos: __import __ (" module. "+ submodule_name_string) –

+0

El siguiente código da como resultado un AttributeError: 'mod = __import __ (" os.path "); mod.join' mientras que el siguiente no: 'mod = importlib.import_module (" os.path "); mod.join' –

+0

oh Veo, tienes razón, pero he hecho lo siguiente para obtener el método os.path.join: getattr (sys.modules ["os.path"], "join") –

Cuestiones relacionadas