Daten eines Decorators verfügbar machen

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
regedit85
User
Beiträge: 5
Registriert: Dienstag 27. Juli 2010, 19:11

Hallo,

ich bin neu bei Python, so bitte entschuldigt es, wenn meine Frage recht Anfängerhaft ist.

Grundsätzlich wollte ich fragen, ob und wie es möglich wäre, die Daten eines Decorators in der decorierten Methode verfügbar machnen kann. Wenn ich z.B. einen Pickle-Decorator hätte, mit dem ich vor dem Methodenaufruf die Daten lade und nach dem Methodenaufruf die Daten wieder zurückschreibe. Aber wie könnte ich auf die geladenen Daten zugreifen? So auf die Schnelle würde ich mir mit einer statischen Variable helfen. Doch jetzt wird es schwierig, wenn ich mehrere Threads habe z.B. eine cherrypy Anwendung, bei der ich die Daten in einem File speichere und sie für jeden Request neu lade und speichere (ob das jetzt aus Concurrency-Gründen Sinn macht sei jetzt dahingestellt, es soll ja nur als Beispiel dienen).

Gibt es etwa in Python eine Möglichkeit das elegant zu lösen, oder die Daten irgendwie wieder zurückgeben kann?

bye
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Einfach die Daten als Parameter an die dekorierte Funktion übergeben.

Sebastian
Das Leben ist wie ein Tennisball.
mjacob
User
Beiträge: 7
Registriert: Dienstag 30. Dezember 2008, 20:09

Hallo,
aus deiner Fragestellung wird nicht ganz deutlich, worauf deine Frage bezogen ist. Du würdest uns sehr helfen, wenn du ein kleines Codebeispiel postest. Allgemein zur Benutzung von Decoratoren, empfehle ich dir diesen Link.

EDIT: Gerade bemerkt, ist mein erster Beitrag hier...
regedit85
User
Beiträge: 5
Registriert: Dienstag 27. Juli 2010, 19:11

@EyDu: 15 Minuten, nachdem ich es gepostet hatte, kam mir auch schon die Idee ;) . Code ist weiter unten. Was meint der Experte? Was mir noch missfällt ist das "*args, **kwargs" in der Definition von test_function...

@mjacob: Codebeispiel ist weiter unten ;)

Code: Alles auswählen

#!/usr/bin/python

def pickle_decorator(f):
	def call_function(*args, **kwargs):
		pickle_data = "data read from pickled file"
		result = f(*args, __pickle_data = pickle_data, **kwargs)
		return result
	return call_function

@pickle_decorator
def test_function(*args, **kwargs):
	print "pickle:", kwargs["__pickle_data"]

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

EyDu hat geschrieben:Einfach die Daten als Parameter an die dekorierte Funktion übergeben.
Oder an den Dekorator. Hängt wohl ab wie man die Aufgabenstellung interpretiert.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Warum nicht so (ungetestet)?

Code: Alles auswählen

def pickle_decorator(f):
   def call_function(*args, **kwargs):
      pickle_data = "data read from pickled file"
      return f(pickle_data, *args, **kwargs)
   return call_function

@pickle_decorator
def test_function(pickle_data):
   print "pickle:", pickle_data

test_function()
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Wieso nutzt man dafür überhaupt einen Dekorator. Das riecht arg nach sehr schlechtem Design hier.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

DasIch hat geschrieben:Wieso nutzt man dafür überhaupt einen Dekorator. Das riecht arg nach sehr schlechtem Design hier.
Vielleicht ein persistentes memoize ;)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
regedit85
User
Beiträge: 5
Registriert: Dienstag 27. Juli 2010, 19:11

@ms4py: geht natürlich auch. Ich hatte nur die Defaultmethode von cherrypy im Hinterkopf, bei der die Position der Argumente auch noch einen Unterschied machen.

@DasIch: Für Verbesserungsvorschläge bin ich immer offen. Ursprünglich wollte ich den einzelnen Requestmethoden einer cherrypy-Anwendung ein SQLAlchemie-Sessionobjekt verfügbar machen (ähnlich wie Turbogears, doch leider hatte ich die Zeit und Muse noch nicht, mir den Code anzusehen). Die Idee wurde dann auf pickle und ähnliches ausgeweitet, das in bestimmten Methoden gemacht werden muss und immer den selben Code benötigt.

bye
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

regedit85 hat geschrieben:@DasIch: Für Verbesserungsvorschläge bin ich immer offen. Ursprünglich wollte ich den einzelnen Requestmethoden einer cherrypy-Anwendung ein SQLAlchemie-Sessionobjekt verfügbar machen (ähnlich wie Turbogears, doch leider hatte ich die Zeit und Muse noch nicht, mir den Code anzusehen). Die Idee wurde dann auf pickle und ähnliches ausgeweitet, das in bestimmten Methoden gemacht werden muss und immer den selben Code benötigt.
Dann nimm eine Klasse, dafür sind die da.

Code: Alles auswählen

class HasPickleData(object):
    def __init__(self, file):
        self.pickle_data = ...


class App(HasPickleData):
    def index(self):
        print self.pickle_data
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

regedit85 hat geschrieben:@DasIch: Für Verbesserungsvorschläge bin ich immer offen. Ursprünglich wollte ich den einzelnen Requestmethoden einer cherrypy-Anwendung ein SQLAlchemie-Sessionobjekt verfügbar machen (ähnlich wie Turbogears, doch leider hatte ich die Zeit und Muse noch nicht, mir den Code anzusehen). Die Idee wurde dann auf pickle und ähnliches ausgeweitet, das in bestimmten Methoden gemacht werden muss und immer den selben Code benötigt.
Bei SQLAlchemy nutzt man dafür am besten eine globale scoped_session, dahinter versteckt sich ein Pool mit Datenbankverbindungen und du bekommst die jeweils lokale in deinem Kontext ob der ein Thread, Greenlet oder was auch immer ist.

Die Frage die sich mir momentan stellt ist wofür du genau pickle nutzt.
regedit85
User
Beiträge: 5
Registriert: Dienstag 27. Juli 2010, 19:11

Danke für den Tipp, DasIch. Es würde also wie folgt aussehen:

Code: Alles auswählen

# irgendwo global
Session = scoped_session(sessionmaker("sqlite://"))

# ...
# wenn ich dann eine session benötige
sess = Session()
sess.close()
Auf die Idee mit pickle bin ich nur gekommen, da ich mich derzeit in SQLAlchemy einlese, und noch nicht so weit bin damit das Objektmodel in die Datenbank zu bekommen. Da ich derzeit ja eine Zugriff habe (den meinen) sollte ich keine Probleme mit den Treads bekommen. Die Idee mit den Dekoratoren hatte ich, da der Code ja immer der selbe ist und immer gemacht werden muss, bevor (oder nachdem) man mit den Daten gearbeitet hat. So würde man z.B. auch nicht das Schliessen der Session vergessen.

bye
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Dazu gibts doch auch den `ContextManager` mit `with`.

Code: Alles auswählen

class MyData(object):
    def __init__():
        self.conn = open_connection()

    def __enter__():
        return self.conn
        
    def __exit__():
        self.conn.close()
        
with MyData() as data:
    process(data)
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Das geht viel eleganter mit contextlib.contextmanager

Code: Alles auswählen

from contextlib import contextmanager

@contextmanager
def db_connection():
    connection = open_connection()
    try:
        yield connection
    finally:
        connection.close()
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

DasIch hat geschrieben:Das geht viel eleganter mit contextlib.contextmanager
Ansichtssache ;) Mir gefällt meine Lösung besser :P
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
regedit85
User
Beiträge: 5
Registriert: Dienstag 27. Juli 2010, 19:11

Danke für den Tipp. Ich werde mir das with Statement mal genauer anschauen (so lernt man dazu).

bye
Antworten