2012-05-10 18 views
6

Si defino un módulo módulo con un directorio correspondiente de module/, ¿puedo cargar dinámicamente las clases de módulos secundarios como a.py o b.py?¿Cómo carga dinámicamente las clases de python desde un directorio determinado?

--module
----a.py
----b.py

¿Se requiere conocer el nombre de la clase a buscar? ¿Podría configurar una clase base que de alguna manera cargar estos niños?

El caso de uso básico es permitirle al usuario escribir un código propio en el que se cargará el programa. Lo mismo que cómo los rieles le permiten escribir sus propios controladores, vistas y modelos en ciertos directorios.

El código para los módulos de carga dinámica hasta ahora que tengo es

def load(folder): 
    files = {} 
    for filename in os.listdir(folder): 
     if (filename[0] != '_' and filename[0] != '.'): 
     files[filename.rstrip('.pyc')] = None 

    # Append each module to the return list of modules 
    modules = [] 
    mod = __import__(folder, fromlist=files.keys()) 
    for key in files.keys(): 
     modules.append(getattr(mod, key)) 

    return modules 

Tenía la esperanza de modificarlo para devolver los objetos de la clase.

+0

Si marca otras preguntas [SE] (http://stackoverflow.com/questions/193161/what-is-the-best-project-structure-for-a-python-application) sobre la estructura de datos de los módulos de python, la tercera respuesta da una muy buena respuesta corta. Supongo que podrías hacer algo como: 'from module import a' dinámicamente. – Zenon

Respuesta

2

que busca pkgutil.walk_packages. El uso de este se puede hacer lo siguiente:

def load(root_import_path, is_valid=lambda entity: True): 
    """Returns modules in ``root_import_path`` that satisfy the ``is_valid`` test 

    :param root_import_path: An string name for importing (i.e. "myapp"). 
    :param is_valid: A callable that takes a variable and returns ``True`` 
        if it is of interest to us.""" 

    prefix = root_import_path + u"." 
    modules = [] 

    for _, name, is_pkg in walk_packages(root_import_path, prefix=prefix): 
     if is_pkg: 
      continue 
     module_code = __import__(name) 
     contents = dir(module_code) 
     for thing in contents: 
      if is_valid(thing): 
       modules.append(thing) 

    return modules 

Alternatly, si no te importa coger en una dependencia, puede probar con el cargador de straight.plugin, que es un poco más complicado que este simple función load.

2
#!/usr/bin/env python 

import os 
import sys 
import inspect 

def load_modules_from_path(path): 
    """ 
    Import all modules from the given directory 
    """ 
    # Check and fix the path 
    if path[-1:] != '/': 
     path += '/' 

    # Get a list of files in the directory, if the directory exists 
    if not os.path.exists(path): 
     raise OSError("Directory does not exist: %s" % path) 

    # Add path to the system path 
    sys.path.append(path) 
    # Load all the files in path 
    for f in os.listdir(path): 
     # Ignore anything that isn't a .py file 
     if len(f) > 3 and f[-3:] == '.py': 
      modname = f[:-3] 
      # Import the module 
      __import__(modname, globals(), locals(), ['*']) 

def load_class_from_name(fqcn): 
    # Break apart fqcn to get module and classname 
    paths = fqcn.split('.') 
    modulename = '.'.join(paths[:-1]) 
    classname = paths[-1] 
    # Import the module 
    __import__(modulename, globals(), locals(), ['*']) 
    # Get the class 
    cls = getattr(sys.modules[modulename], classname) 
    # Check cls 
    if not inspect.isclass(cls): 
     raise TypeError("%s is not a class" % fqcn) 
    # Return class 
    return cls 

def main(): 
    load_modules_from_path('modules') 
    # load the TestClass1 
    class_name = load_class_from_name('class1.TestClass1') 
    # instantiate the Testclass1 
    obj = class_name() 
    # using this object obj to call the attributes inside the class 
    print obj.testclass1() 

if __name__ == '__main__': main() 

Dentro directorio de módulos, i ve otros dos módulos para la prueba:

[♫ test] modules :~ pwd 
/tmp/dynamic_loader/modules 

[♫ test] modules :~ ls -lR 
total 32 
-rw-r--r-- 1 staff staff 138 Aug 30 21:10 class1.py 
-rw-r--r-- 1 staff staff 575 Aug 30 21:11 class1.pyc 
-rw-r--r-- 1 staff staff 139 Aug 30 21:11 class2.py 
-rw-r--r-- 1 staff staff 576 Aug 30 21:11 class2.pyc 

[♫ test] modules cat class1.py 

class TestClass1(object): 
    def testclass1(self): 
     print 'I am from testclass1' 

    def some_function(): 
     print 'some function 1' 
Cuestiones relacionadas