2017-01-24 3 views
0

Jede Geschäftsregel, die ich erstelle, wird in einen Ordner namens "rule_definitions" gestellt.Python OOP importiert untergeordnete Klasse von der übergeordneten Klasse

Ich habe eine Klasse Rule. Es fungiert als Vorlage für all diese erstellten Regeln, von denen sie die notwendigen generischen Funktionen übernehmen können.

Ein Beispiel für den Inhalt des Ordners:

rule_definitions/ 
    discard.py 
    saveValue.py 
    storeValue.py 
    writeToOutput.py 

Aber wenn Sie eine Instanz einer Regel erstellen möchten, es ist sehr sauber, nur tun:

rule = Rule('discard') und haben die Rule Klasse den Import tun selbst, anstatt jedes Mal das passende Regelmodul zu finden, wenn Sie eine Regel laden müssen.

Zum Beispiel könnte der Gehalt an rule_definitions.py sein:

from Rule import Rule 

class _discard(Rule): 
    ... 

Und innerhalb Rule, könnten wir haben:

import importlib 

class Rule(): 
    """A template class that all rules inherit from and are instantiated from.""" 

    def __init__(self, rule): 
     # load the rule by name from rule definitions 
     try: 
      self.Rule = importlib.import_module('defs._'+ rule) 
     except ImportError: 
      print 'Failed to find rule definiton while attempting to load 


    #other generic functions to inherit below 

Ist dies der sauberste Weg? Ich bin mir nicht sicher, ob das Standardverfahren wäre.

Antwort

1

Es gibt ein paar Probleme hier. Lassen Sie mich tun es eins nach dem anderen:

  • Was Sie vorschlagen, wirklich _discard nicht erfordert von Rule zu erben. Sie verwenden sowohl Vererbung als auch Komposition, was verwirrend aussieht.

  • Die von Ihnen zurückgegebene Regel hat immer noch den Typ Rule, nicht _discard. Vielleicht ist das, was Sie wollen, vielleicht nicht ...

  • Rule('discard') kann nicht statisch überprüft werden und wird nicht Autovervollständigung erhalten Sie erwarten (wenn Sie IDE verwenden).

Hier sind einige Ideen für Verbesserungen:

  • reine Zusammensetzung: die aktuelle Initialisierung halten, aber erben nicht von Rule. Verwenden Sie entweder eine andere Klasse für die generische Funktionalität oder übergeben Sie das übergeordnete Element an den Konstruktor _discard. (Die zweite wird Bezug erzeugen Schleifen obwohl)

Mit anderen Klasse für allgemeine Funktionalität es so aussehen kann:

class RuleTrait(object): 
    def some_common_stuff(self): 
     ... 

class _discard(RuleTrait): 
    def do_work(self): 
     some_common_stuff() 

class Rule(object): 
    def __init__(self, typ): 
     self.impl = _get_impl_by_name(typ) 

    def __getattr__(self, name): 
     return getattr(self.impl, name) 

Rule("discard").do_work() # this will be forwarded to _discard.do_work 
  • Actual Vererbung: Seien Sie nicht den generischen Konstruktor verwenden, aber die direkten Klassen stattdessen. Rule('discard') ist nicht schlechter als rules.Discard(), und es wird Ihnen bessere Typprüfungen geben. Und Sie können die Import-Magie loswerden.

  • Wenn Sie mehr Import Magie in einigen Fällen benötigen, machen Sie es stattdessen eine Fabrik. Rule(...) kann nur ein Rule Objekt erstellen. Aber Sie können stattdessen eine make_rule('discard') mit der Implementierung schreiben, die Sie benötigen.

+0

Ja, ich möchte, dass in diesem Szenario jede Regel vom Typ 'Rule' ist, nicht' _discard'. Aber eine Frage zu Ihrer ersten Lösung, eine andere Klasse für generische Funktionalität zu verwenden, wie würde das funktionieren? Angenommen, ich habe die 'RuleTemplate' Klasse, die' _discard' und alle anderen erstellten Regeln erben. Wenn ich eine Regel erstelle, z. B .: 'r = Rule ('discard')' - Ich kann die generischen Funktionen wie 'Rule.execute (args)' oder 'Rule.getName()' nicht ausführen. – X33

+1

@ X33 Ich habe eine Probe hinzugefügt. Sie können alle unbekannten Attribute an die tatsächliche Implementierung weiterleiten. Ihre Klasse mit generischen Regelmerkmalen muss jedoch nicht öffentlich sein. – viraptor

+0

Okay, ich verstehe jetzt. Ich schätze die Aufklärung sehr. Dies ist wahrscheinlich der beste Ansatz für meine gegebene Situation. Wenn Sie Zeit haben, habe ich eine abschließende Frage: Ist diese Lösung in Bezug auf den Fabrikansatz nicht sehr ähnlich einer Fabrik? – X33

1

Was Sie tun, ähnelt dem dynamischen Laden von Datenbankmigrationen. Django und ähnliche datenbankbezogene Projekte können Code enthalten, den Sie betrachten könnten.

Ich schrieb einen Code, der automatisches Laden und Importieren ausführt. Blick auf die load_migrations Funktion schrieb ich hier https://github.com/someones/exodus/blob/master/exodus/init.py

  1. Die Kern Exodus Klasse lädt Migrationen von einem bestimmten Verzeichnis.

  2. Jede Datei enthält eine Klasse, die das BaseMigration-Objekt erweitert.

  3. Die Metaklasse von BaseMigration registriert sich selbst mit einer zentralen Liste von Migrationen zur Analysezeit.

Verwandte Themen