Seite 1 von 1

Daten eines Decorators verfügbar machen

Verfasst: Dienstag 27. Juli 2010, 20:34
von regedit85
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

Re: Daten eines Decorators verfügbar machen

Verfasst: Dienstag 27. Juli 2010, 20:55
von EyDu
Hallo und willkommen im Forum!

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

Sebastian

Re: Daten eines Decorators verfügbar machen

Verfasst: Dienstag 27. Juli 2010, 20:58
von mjacob
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...

Re: Daten eines Decorators verfügbar machen

Verfasst: Dienstag 27. Juli 2010, 22:44
von regedit85
@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

Re: Daten eines Decorators verfügbar machen

Verfasst: Dienstag 27. Juli 2010, 22:48
von Leonidas
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.

Re: Daten eines Decorators verfügbar machen

Verfasst: Dienstag 27. Juli 2010, 22:50
von ms4py
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()

Re: Daten eines Decorators verfügbar machen

Verfasst: Dienstag 27. Juli 2010, 23:04
von DasIch
Wieso nutzt man dafür überhaupt einen Dekorator. Das riecht arg nach sehr schlechtem Design hier.

Re: Daten eines Decorators verfügbar machen

Verfasst: Dienstag 27. Juli 2010, 23:29
von Leonidas
DasIch hat geschrieben:Wieso nutzt man dafür überhaupt einen Dekorator. Das riecht arg nach sehr schlechtem Design hier.
Vielleicht ein persistentes memoize ;)

Re: Daten eines Decorators verfügbar machen

Verfasst: Mittwoch 28. Juli 2010, 07:03
von regedit85
@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

Re: Daten eines Decorators verfügbar machen

Verfasst: Mittwoch 28. Juli 2010, 07:54
von Darii
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

Re: Daten eines Decorators verfügbar machen

Verfasst: Mittwoch 28. Juli 2010, 13:30
von DasIch
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.

Re: Daten eines Decorators verfügbar machen

Verfasst: Mittwoch 28. Juli 2010, 15:23
von regedit85
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

Re: Daten eines Decorators verfügbar machen

Verfasst: Mittwoch 28. Juli 2010, 22:19
von ms4py
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)

Re: Daten eines Decorators verfügbar machen

Verfasst: Mittwoch 28. Juli 2010, 22:31
von DasIch
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()

Re: Daten eines Decorators verfügbar machen

Verfasst: Mittwoch 28. Juli 2010, 23:49
von ms4py
DasIch hat geschrieben:Das geht viel eleganter mit contextlib.contextmanager
Ansichtssache ;) Mir gefällt meine Lösung besser :P

Re: Daten eines Decorators verfügbar machen

Verfasst: Donnerstag 29. Juli 2010, 07:34
von regedit85
Danke für den Tipp. Ich werde mir das with Statement mal genauer anschauen (so lernt man dazu).

bye