2017-09-28 2 views
3

Edit: Ich angegeben haben, sollte ich (fest) arbeiten w/Python 2, aber wäre daran interessiert zu sehen, wie diese entweder in Angriff genommen werden könnte 2 oder 3Magie Einfuhren in Python

Das Szenario: Ich habe ein Paket namens shapes.

Ich habe ein Modul in shapes namens factory, die eine ShapeClassFactory Klasse hat. Diese Klasse kann eine Zeichenfolge übergeben werden. Sie sucht in einer entfernten Datenbank nach Daten und verwendet diese, um eine Klasse dynamisch zu definieren, die zurückgegeben wird.

shapes.py:

from .factory import ShapeClassFactory 
__all__ = ['ShapeClassFactory'] 

In der Praxis dieses Paket in einer Vielzahl von anderen Paketen verwendet werden kann & Skripte, etwa so:

from shapes import ShapeClassFactory 

Circle = ShapeClassFactory("Circle") 
Rect = ShapeClassFactory("Rect") 

myCircle = Circle(r=5, fill='red') 
mySquare = Rect(x=5, y=5, fill=None) 

Das Problem: Die oben ist alles gut. Allerdings würde ich lieben das shapes Paket so zu schreiben, um der Lage sein, die es wie so verwendet werden könnten:

from shapes import Circle, Rect 

myCircle = Circle(r=5, fill='red') 
mySquare = Rect(x=5, y=5, fill=None) 

... die Idee ist, dass, wenn das Mitglied nicht in shapes gefunden, es verwendet ShapeClassFactory, um es zu versuchen und zu generieren.

Die Schwierigkeit besteht darin, dass die verfügbaren Klassen im Grunde nicht bekannt sind, bis sie angefordert werden, so dass eine vordefinierte Liste von Klassennamen nicht hilft.

Ich habe nichts dagegen werfen ImportError wenn ShapeClassFactory scheitert eine Klasse zu bauen - aber ist so etwas überhaupt möglich?

+0

Die Importanweisung wird das Modul ausgeführt, das importiert wird, und dann die angeforderten Namen abrufen. Es gibt keine Möglichkeit vorher zu wissen, welche Namen angefordert werden. Im Prinzip können Sie das nicht tun, ohne etwas wie "__import__" (vielleicht mit Meta-Hooks) zu patchen, und das sollten Sie wirklich nicht tun. Zum Beispiel, was macht dir (shapes)? Der richtige Weg, dies zu tun, ist, was Sie bereits getan haben. –

+1

Wenn die Anzahl der möglichen generierten Klassen ziemlich klein ist, können Sie alle im Namensraum von 'shapes' generieren. Dies wäre auch ein standardmäßiger und vernünftiger Weg, dies zu tun. –

+0

Einer der Hauptgründe, warum ich generierte Klassen verwende, ist, dass ich das Paket nicht aktualisieren muss, wenn ein neuer Shape in der entfernten Datenbank definiert ist. Daher ist das Definieren einer Liste akzeptierter Klassen keine wirkliche Lösung. –

Antwort

0

Sie können dies tun, indem Sie bei der Initialisierung automatisch alle möglichen Objekte im Namespace shapes konstruieren, solange es nicht zu viele mögliche Klassen gibt und die Initialisierungskosten der Klassen nicht zu hoch sind. Sie würden Code wie folgt in shapes.py verwenden:

from .factory import ShapeClassFactory 

__all__ = ['ShapeClassFactory'] 

def get_shape_names(): 
    """Returns all valid shapes that can be passed in to ShapeClassFactory""" 
    return ['Circle', 'Rect'] # your own code should query the database 

for name in get_shape_names(): 
    globals()[name] = ShapeClassFactory(name) 
    __all__.append(name) 
+0

Das Problem dabei ist, dass möglicherweise Dutzende von Klassen verfügbar sind, aber normalerweise nur 2 bis 4 in einem einzelnen Modul oder Skript verwendet werden. Da sowohl die Datenbankabfragen als auch die Klassenkonstruktion selbst erhebliche Kosten verursachen, möchte ich nur die angeforderten Klassen generieren. –

+1

Sie können möglicherweise die Kosten in der Klassenkonstruktion zur Instanziierung übernehmen. Mit anderen Worten, Instanzvariablen verwenden, die in '__init__' und nicht in Klassenvariablen definiert sind. Dies würde bedeuten, dass Sie nur eine Datenbankabfrage benötigen, um die Liste der möglichen Formen abzurufen, und alle anderen Abfragen während der Instantiierung ausgeführt werden. –

+0

Ich fühle mich nicht gut über die Idee, alle Attribute auf der Instanzenebene zu definieren - abgesehen davon, dass es nicht praktisch ist (dh ich möchte einige Klassenmethoden), fühlt es sich so an, als wäre dieser Code ein Rückschritt in Lesbarkeit und Wartbarkeit. Es fühlt sich auch wie eine mögliche Speicherschwemme an, wenn mit einer großen Anzahl von Instanzen gearbeitet wird. –