anfängerfrage: das @

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
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

hi!
ich habe letztens irgendwo (es war bei den decoratoren) ein @ gelesen, dessen bedeutung ich nicht verstanden habe.
nun dachte ich mir, das schaue ich mir mal im wiki an, aber: unter "@" lässt sich nichts finden!
könnte das ins wiki gestellt werden?
http://www.cs.unm.edu/~dlchao/flake/doom/
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Das @ gibt es nur für Dekoratoren. Und die Fausregel ist:

Code: Alles auswählen

@foo
def bar():
 pass
ist das gleiche wie

Code: Alles auswählen

def bar():
 pass
bar = foo(bar)
und folgedem ist auch

Code: Alles auswählen

@foo()
def bar():
 pass
das gleiche wie

Code: Alles auswählen

def bar():
 pass
bar = foo()(bar)
Und mehr gibts dazu nicht zu sagen. Wenn du das noch nie gebraucht hast wird dich auch das "@" nicht interessieren.
TUFKAB – the user formerly known as blackbird
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Na ja, hast recht, wobei solch eine Syntax für Classmethods schon ganz nützlich ist ...

Gruß,
Christian
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

aber was bringt ein decorator?
ich habe zwar http://soiland.no/software/decorator gelesen, konnte dem aber keine informationen entnehmen, stehe irgendwie da auf dem schlacuh.
http://www.cs.unm.edu/~dlchao/flake/doom/
Benutzeravatar
beewee
User
Beiträge: 35
Registriert: Mittwoch 18. Januar 2006, 22:16

aber was bringt ein decorator?
Wie gesagt, du kannst eine Funktion auf die Funktion anwenden. Zum beispiel sinnvoll bei sowas:

Code: Alles auswählen

class abc:
    @property
    def enabled(self):
        return True

b = abc()
b.enabled # b.enabled, nicht b.enabled()
BeeWee
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Sinnvoll sind Dekoratoren zb, um funktionen zu "wrappen".

Gegeben sei zB die Situation, dass eine Art Zugriffsgenehmigung auf Funktionsebene gebraucht ist (hat man häufig in webframeworks).

Man hat viele recht einfache Funktionen, die vom Endbenutzer eines Frameworks geschrieben werden sollen:

Code: Alles auswählen

def pageA(request):
  print "Hello world!"

def pageB(request):
  print "Hello Again!"
Jetzt möchte der Entwickler der Bibliothek diesen Benutzern recht einfach ermöglichen, Sicherheitschecks zu machen. Er macht also einen Dekorator, der in etwa so aussieht:

Code: Alles auswählen

def permissionRequired(unsafeFunction):
  def wrapper(*args, **kwargs):
    if user_has_permission:
      unsafeFunction(*args, **kwargs)
    else:
      print "Breakin' the Law!"
  return wrapper
Es ist eine Funktion, der einen Wrapper für die übergebene Funktion erzeugt.
Diese Funktion kann nun als Dekorator genutzt werden:

Code: Alles auswählen

@permissionRequired
def pageB(request):
  print "Hello Again!"
Das sorgt dafür, dass an den Namen "pageB" nicht mehr die eigentliche funktion pageB gebunden ist, sondern das resultat von permissionRequired(pageB), welches "im prinzip" die funktion B mit einem sicherheitscheck ist.

Es gibt noch einen ganzen Haufen anderer Verwendungen für Dekoratoren, aber diese ist mir bis jetzt am häufigsten untergekommen.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

murph hat geschrieben:aber was bringt ein decorator?
Ein Dekorator ist nur "syntactic sugar", der statt

Code: Alles auswählen

def bar():
 pass
bar = foo(bar)
folgende Form erlaubt:

Code: Alles auswählen

@foo
def bar():
 pass
Man spart sich dabei, den Funktionsnamen zweimal zu wiederholen und rückt die Dekoration näher an die Funktionsdefinition, wo man sie schneller erfassen kann.
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

an sich also ganz gut, wenn man bei jedem aufruf einer funktion bestimmte sachen testen möchte etc.

Code: Alles auswählen

def permissionRequired(unsafeFunction):
  def wrapper(*args, **kwargs):
    if user_has_permission:
      unsafeFunction(*args, **kwargs)
    else:
      print "Breakin' the Law!"
  return wrapper
in diesem fall wird beim aufruf einer beliebigen funktion, die nach dem dekorator genannt wird, erst der dekorator aufgerufen, dann überprüft, ob der user die rechte hat, und dann vom wrapper die gewünschte funktion ausgeführt...aber die funktion wird doch automatisch ausgeführt, wenn man sie für einen aufruf benutzt!?! oder wenn man dieses nicht tut, dann sind aber alle argumente in einem tuple, d.h., wenn das ganze auf etwas noch anderem basiert, muss man erstmal den kladderadatsch aus dem tuple holen...oder?
http://www.cs.unm.edu/~dlchao/flake/doom/
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

kennt wer ein gutes tutorial dazu?
habe grade genau das richtige für einen wrapper, muss aber bisschen daran rumschrauben.
Danke im Voraus!
http://www.cs.unm.edu/~dlchao/flake/doom/
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Hier wäre eventuell was brauchbares ...

Ist zwar kein richtiges Tutorial (eher ein HowTo) dafür aber echt brauchbar.

Für Beispiele kann man ja mal hier vorbeischauen ...
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

thx
http://www.cs.unm.edu/~dlchao/flake/doom/
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

in diesem fall wird beim aufruf einer beliebigen funktion, die nach dem dekorator genannt wird, erst der dekorator aufgerufen,
jein, das stimmt so nicht ganz. es wird nicht "erst" der dekorator, sondern _nur_ die funktion, die der dekorator zurückgibt, aufgerufen.

man stelle sich vor, man riefe diesen dekorator von hand auf

Code: Alles auswählen

def innocentFunction(a, b, c):
  print a, b, c

# punkt 1

innocentFunction= permissionRequired(innocentFunction)

# punkt 2
man sieht hier: bei punkt 1 ist an den Namen "innocentFunction" eine Funktion gebunden, die a, b, c ausgibt (logisch).
Allerdings wird dieser name nach punkt 1 neu gebunden, und zwar an das resultat der funktion permissionRequired, die auch eine funktion zurückgibt.
dann überprüft, ob der user die rechte hat, und dann vom wrapper die gewünschte funktion ausgeführt...aber die funktion wird doch automatisch ausgeführt, wenn man sie für einen aufruf benutzt!?!
nein, weil diese funktion ja nicht mehr mit diesem namen verknüpft ist.
der name "innocentFunction" ist an den wrapper gebunden, den "permissionRequired" zurückgegeben hat, das ganze ding ist in jeder hinsicht einfach nur eine funktion.
oder wenn man dieses nicht tut, dann sind aber alle argumente in einem tuple, d.h., wenn das ganze auf etwas noch anderem basiert, muss man erstmal den kladderadatsch aus dem tuple holen...oder?
ich verstehe nicht ganz, was du hier meinst.

edit: ich bastele gerade im Pythonwiki an einer Einführung. Anregungen oder Korrekturen sind erwünscht :)
Antworten