Klasseninstanz aus String erzeugen: obj = "ClassN"

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
ChrisGTJ
User
Beiträge: 105
Registriert: Mittwoch 22. August 2007, 15:45

Hallo, ich noch mal.

bezugnehmend auf meinen anderen Thread

http://www.python-forum.de/viewtopic.php?p=78396#78396

ergibt sich eine weitere Frage:

Wir haben den Namen einer Klasse als String und möchten den Namen nun als Klasse behandelt sehen und eine Instanz davon erzeugen. Im Prinzip suche ich sowas wie ein annonymes getattr():

Code: Alles auswählen


class ClassN( object):
    pass

obj = get_instance_from_name( "ClassN")

Gibt es sowas?

Gruß,

Christoph
BlackJack

Klassen sind Attribute des Moduls in dem sie stecken. Also funktioniert das normale `getattr()` mit dem Modul. Immer dran denken: in Python ist alles ein Objekt.

Code: Alles auswählen

import motoren
motor = getattr(motoren, 'SuperMotor')()
Erzeugt einen `motoren.SuperMotor`.
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

Hallo,

ich möchte den obigen Beitrag noch einmal aufgreifen: Ich habe ein Package, in dem sich eine beliebige Anzahl mir unbekannter Module befindet, in denen sich jeweils eine Klasse befindet. Klasse und Modul haben den selben Namen.

Das Package wird mit from package import * importiert.

Jetzt habe ich einen String (aus einer Datenbank), der den Namen der zu instanziierenden Klasse enthält.
getattr funktioniert mit dem Package nicht - wie kann ich jetzt an meine Instanz rankommen?

Vielen Dank

Jan-Peer
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Jan-Peer hat geschrieben:Jetzt habe ich einen String (aus einer Datenbank), der den Namen der zu instanziierenden Klasse enthält.
getattr funktioniert mit dem Package nicht - wie kann ich jetzt an meine Instanz rankommen?
Module mit Stern-Importen reinzuziehen ist fast immer eine schlechte Idee. Daher lass das lieber.

Wenn du dann den Klassennamen hast, ist das simpel:

Code: Alles auswählen

import package
getattr(getattr(package, 'Modulname'), 'Klassenname')
(ungetestet)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Moin,
Jan-Peer hat geschrieben:[...]
Klasse und Modul haben den selben Namen.

Das Package wird mit from package import * importiert.

Jetzt habe ich einen String (aus einer Datenbank), der den Namen der zu instanziierenden Klasse enthält.
versuch mal:

Code: Alles auswählen

cls = eval('%s.%s' % (name, name))
Ob das 'from package import *' aber wirklich Sinn macht? Vielleicht wäre folgendes besser:

Code: Alles auswählen

module_name = '%s.%s' % (package, name)
module = __import__(module_name, globals(), locals(), [name])
cls = getattr(module, name)
Oder so ähnlich :wink: .

Gruß,
Manuel
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

Ist leider nicht ganz so einfach:

Code: Alles auswählen

>>> import campaigns
>>> getattr(getattr(campaigns, "Campaign"), "Campaign")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'module' object has no attribute 'Campaign'

Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Kannst du denn auf ``campaign.Campaign`` im Interpreter zugreifen?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

@leonidas:

Nein, komischerweise auch nicht. Hab ich beim aufsetzen des Packages was falsch gemacht?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Was gibt denn ``dir(campaign)`` aus? Da sind die meisten Namen auf die du zugreifen kannst (es kann durchaus mehr Namen geben, als ``dir()`` anzeigt, aber das ist selten).
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

Zwei Fragen: Ist es überhaupt ein Package, also ist die `__init__.py` vorhanden? Und liegt das Package in `sys.path`?
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

``dir()`` gibt builtins, doc, file, name und path aus

Die __init__.py ist vorhanden, wenn auch leer. Das Package liegt im Arbeitsverzeichnis, sollte also erreichbar sein. (Wenn ich direkt mit den Klassenamen arbeite, also campaigns.Campaign.Campaign(), geht es)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Jan-Peer hat geschrieben:``dir()`` gibt builtins, doc, file, name und path aus
Du musst schon ``dir(campaign)`` machen (wie ich schon schrieb), sonst zeigt er dir den lokalen Namespace an, was eher uninteressant ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

Hab ich gemacht, war jetzt bloß zu faul, die paar Zeichen noch mit in die Klammern zu setzen. Sieht also eher unbefriedigend aus.

Aber vielleicht gibt es ja auch noch einen intelligenteren Ansatz für mein Problem:

Ich schreibe an einer Anwendung zur Verwaltung von Werbeaktionen. Es gibt eine abstrakte Klasse ("Campaign"), von der sich wiederum die eigentlichen Typklassen ableiten. Ich möchte das System möglichst offen halten, d.h. wenn ich einen neuen Aktionstyp einführe, möchte ich die benötigte Klasse im Idealfall einfach nur in ein bestimmtes Verzeichnis (hier kommt das Package ins Spiel) kopieren müssen. Ach ja: Irgendwie müsste sich dann auch noch eine Liste der verfügbaren Typen (= Klassennamen) erzeugen lassen.

Wenn jemand einen schöneren Ansatz kennt, darf er mich gerne auf den richtigen Pfad leuchten ;-)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Jan-Peer hat geschrieben:Ich schreibe an einer Anwendung zur Verwaltung von Werbeaktionen. Es gibt eine abstrakte Klasse ("Campaign"), von der sich wiederum die eigentlichen Typklassen ableiten. Ich möchte das System möglichst offen halten, d.h. wenn ich einen neuen Aktionstyp einführe, möchte ich die benötigte Klasse im Idealfall einfach nur in ein bestimmtes Verzeichnis (hier kommt das Package ins Spiel) kopieren müssen. Ach ja: Irgendwie müsste sich dann auch noch eine Liste der verfügbaren Typen (= Klassennamen) erzeugen lassen.
Plugin-System? What's on Air hat genau sowas.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

Besten Dank,

ich hab mich davon mal inspirieren lassen und eine mich zufriedenstellende Lösung gefunden.
Antworten