2012-05-10 16 views
6

Wenn ich ein Modul Modul mit einem entsprechenden Verzeichnis von module/ definieren, kann ich dynamisch Klassen von Kindermodulen wie a.py oder b.py laden?Wie laden Sie Python-Klassen dynamisch aus einem bestimmten Verzeichnis?

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

Dies erfordert den Klassennamen zu suchen wissen? Kann ich eine Basisklasse einrichten, die diese Kinder irgendwie lädt?

Der grundlegende Anwendungsfall besteht darin, einem Benutzer das Schreiben eines eigenen Codes zu ermöglichen, in den das Programm geladen wird. Dasselbe wie Rails Ihnen ermöglicht, Ihre eigenen Controller, Ansichten und Modelle in bestimmten Verzeichnissen zu schreiben.

Der Code für das Laden von Modulen dynamisch habe ich so weit ist

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 

Ich hatte gehofft, es zu ändern Klassenobjekte zurückzukehren.

+0

Wenn Sie andere überprüfen [SE Fragen] (http://stackoverflow.com/questions/193161/Was ist die beste Projekt-Struktur für eine Python-Anwendung?) über Python-Module Datenstruktur, die dritte Antwort geben eine ziemlich gute kurze Antwort. Ich schätze, als könnte man etwas tun wie: 'von Modul Import a 'dynamisch. – Zenon

Antwort

2

Sie suchen pkgutil.walk_packages. Diese verwenden Sie Folgendes ausführen können:

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, wenn Sie nicht auf eine Abhängigkeit Einnahme nichts ausmacht, können Sie den straight.plugin loader versuchen, die ein wenig komplizierter als diese einfache load Funktion ist.

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() 

Innen modules, ich habe zwei weitere Module für die Prüfung:

[♫ 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' 
Verwandte Themen