2016-07-03 9 views
2

Angesichts der folgenden Paketstruktur:Stellen Sie alle Klassen in einem Paket als Klassenattribute

master.py 
models/ 
    __init__.py 
    model1.py 
    model2.py 
    model3.py 

wo jedes Modell * .py-Datei eine oder mehrere Klassen enthält, wie kann ich eine Klasse in master.py erstellen, die dynamisch Importe jede dieser Klassen und setzt es als ein Attribut von sich selbst? Derzeit habe ich folgendes:

class DB: 
    def __init__(self): 
     from models.model1 import foo, bar 
     from models.model2 import foo2 
     from models.model3 import bar2 

     self.foo = foo 
     self.bar = bar 
     self.foo2 = foo2 
     self.bar2 = bar2 

aber dies erfordert, dass ich jedes importierte Modul und Klasse explizit angeben. Ich möchte, dass der Prozess automatisch/soft-codiert wird, sodass ich die DB-Klasse nicht aktualisieren muss, wenn ich später Modelle hinzufüge oder entferne.

Antwort

0

Nun ... ich denke nicht, dass es die beste Weg ist, dies zu tun - würde ich persönlich bevorzugen, alle Importe manuell zu behandeln. Aber ich nehme an, Sie haben Ihre Gründe und beantworten Ihre Frage trotzdem.

Zunächst benötigen Sie die models, um ein Modul zu sein, also fügen Sie eine Datei models/__init__.py bevor Sie fortfahren.

import inspect 
import os 
import sys 

class DB(object): 
    def __init__(self): 
     # Get current file (`master.py`)'s directory and the `models` directory. 
     selfdir = os.path.dirname(os.path.abspath(__file__)) 
     models_dir = os.path.join(selfdir, 'models') 
     # Get all files in `models` that are Python files. 
     models_files = [file for file in os.listdir(models_dir) if os.path.isfile(os.path.join(models_dir, file)) and file.endswith('.py')] 
     model_names = [model[:-3] for model in models_files] 
     for model_name in model_names: 
      # Exploit Python's ability to execute arbitrary code. 
      module_name = 'models.{name}'.format(name=model_name) 
      exec("import {module}".format(module=module_name)) 
      module = sys.modules[module_name] 
      classes = inspect.getmembers(module, inspect.isclass) 
      for module_class in classes: 
       setattr(self, module_class[0], module_class[1]) 

Getestet habe ich es (in 2.7.11) und es funktioniert super, so lassen Sie mich wissen, wenn etwas für Sie nicht funktioniert. Es gibt ein paar Vermutungen, die Sie in Ihrer Codebasis, wahrscheinlich über Dokumentation, nur garantieren müssen. Ich habe nicht die IO-Ausnahmen behandelt, die ich wahrscheinlich mit dem Verzeichnis models haben sollte, aber Sie können hinzufügen, dass ich denke. Außerdem könnte jemand einen cleveren Dateinamen erstellen und willkürliche Codeausführung erzwingen. Also sei vorsichtig.

+0

Interessant; Ich möchte nur ein bisschen herumspielen, bevor ich es richtig ankreuze, hoffe es macht dir nichts aus. Und du hast Recht - Modelle sind ein Paket, ich habe vergessen, __init__.py in meinem Beispiel zu zeigen – Noah

+0

@Noah keine Sorgen! –

Verwandte Themen