function decorator
-
- User
- Beiträge: 148
- Registriert: Sonntag 2. November 2008, 12:13
hallo miteiander
habe im netz nach erklärung von function decorator gesucht, aber leider nichts verständliches gefunden. Könnte jemand mir bitte erklären was function decoratoren sind?
Vielen Dank kostonstyle
habe im netz nach erklärung von function decorator gesucht, aber leider nichts verständliches gefunden. Könnte jemand mir bitte erklären was function decoratoren sind?
Vielen Dank kostonstyle
-
- User
- Beiträge: 148
- Registriert: Sonntag 2. November 2008, 12:13
habe ein beispiel aus dem buch python
die ausgabe
das programm holt, die berechneten Zahlen aus dem Speicher.
Ich habe mal versucht das Programm zu beduggen und habe folgendes festgestellt.
Der Decorator führt zuerst den Programmcode aus, der hinter @ steht. Danach geht er wieder zurück nach fak funktion und anschliessend geht er wieder zurück in die klasse.
Das war zwar keine grosse feststellung.....
Gruss kostonstyle
Code: Alles auswählen
class CacheDecorator(object):
def __init__(self):
self.cache = {}
self.func = None
def cachedFunc(self, *args):
if args not in self.cache:
self.cache[args] = self.func(*args)
return self.cache[args]
def __call__(self, func):
self.func = func
return self.cachedFunc
@CacheDecorator()
def fak(n):
ergebnis = 1
for i in xrange(2, n+1):
ergebnis *= i
return ergebnis
print(fak(20))
print(fak(12))
print(fak(29))
print(fak(20))
print(fak(30))
Code: Alles auswählen
2432902008176640000
479001600
8841761993739701954543616000000
2432902008176640000
265252859812191058636308480000000
Ich habe mal versucht das Programm zu beduggen und habe folgendes festgestellt.
Der Decorator führt zuerst den Programmcode aus, der hinter @ steht. Danach geht er wieder zurück nach fak funktion und anschliessend geht er wieder zurück in die klasse.
Das war zwar keine grosse feststellung.....
Gruss kostonstyle
Ein Dekorator wird mit dem dekorierten Objekt aufgerufen, welches mit dem Objekt ersetzt wird dass der Dekorator zurückgibt. Üblicherweise gibt der Dekorator die gleiche Funktion/Klasse modifiziert oder gewrappt zurück.
Das von dir gezeigte Beispiel ist nicht so gut, man würde dafür üblicherweise eine Funktion nehmen.
Das von dir gezeigte Beispiel ist nicht so gut, man würde dafür üblicherweise eine Funktion nehmen.
Code: Alles auswählen
from functools import wraps
def cached(func):
cache = {}
@wraps(func)
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
- cofi
- Python-Forum Veteran
- Beiträge: 4432
- Registriert: Sonntag 30. März 2008, 04:16
- Wohnort: RGFybXN0YWR0
Weil DasIch noch nicht explizit gesagt hat (und mir das geholfen hat Dekoratoren zu verstehen):
ist dasselbe wie
Code: Alles auswählen
@wrap
def func():
...
Code: Alles auswählen
def func():
...
func = wrap(func)
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
Das gezeigt Beispiel ist vor allem nicht gut, weil man mit Keyword-Argumenten Probleme kriegt und es Namenskonventionen nicht beachtet, aber gegen Klassen ist nichts einzuwenden.DasIch hat geschrieben:Das von dir gezeigte Beispiel ist nicht so gut, man würde dafür üblicherweise eine Funktion nehmen.
- birkenfeld
- Python-Forum Veteran
- Beiträge: 1603
- Registriert: Montag 20. März 2006, 15:29
- Wohnort: Die aufstrebende Universitätsstadt bei München
Was für Namenskonventionen? Wie auch immer, hier eine Klasse zu verwenden, ist eindeutig Overkill. Genau dafür sind Closures doch da. "Gegen Klassen ist nichts einzuwenden" -- sagst du das auch dem Java-Programmierer, der eine Klasse "Main" schreibt, nur um eine "main"-Methode aufzurufen?Darii hat geschrieben:Das gezeigt Beispiel ist vor allem nicht gut, weil man mit Keyword-Argumenten Probleme kriegt und es Namenskonventionen nicht beachtet, aber gegen Klassen ist nichts einzuwenden.DasIch hat geschrieben:Das von dir gezeigte Beispiel ist nicht so gut, man würde dafür üblicherweise eine Funktion nehmen.
cachedFunc, aber ist nicht so wild, ich halte mich ja bei meinem Beispiel unten auch nicht dranbirkenfeld hat geschrieben:Was für Namenskonventionen?

Findest Dekorator-Funktionen wirklich immer lesbarer als Klassen? Wenn es der Lesbarkeit/Strukturierung dient, ist gegen eine Klasse nichts einzuwenden. Zumal manche Sachen ohne ``nonlocal`` wirklich „hacky“ werden, nur mit closures.Wie auch immer, hier eine Klasse zu verwenden, ist eindeutig Overkill. Genau dafür sind Closures doch da.
Code: Alles auswählen
class cached(object):
def __init__(self, func):
self.cache = {}
self.func = func
def __call__(self, *args, **kwargs):
cache_key = (args, tuple(kwargs.items()))
if cache_key not in self.cache:
self.cache[cache_key] = self.func(*args, **kwargs)
return self.cache[cache_key]
@cached
def fac(n):
if not n: return 1
return n*fac(n-1)
Sei doch ehrlich, der Vergleich hinkt. Das wäre nur ein Fall von: Java-Kenntnisse unreflektiert auf Python übertragen."Gegen Klassen ist nichts einzuwenden" -- sagst du das auch dem Java-Programmierer, der eine Klasse "Main" schreibt, nur um eine "main"-Methode aufzurufen?
-
- User
- Beiträge: 148
- Registriert: Sonntag 2. November 2008, 12:13
bitte das Thema nicht noch komplizierter machen, bleiben wir bei der Sache.
bei diesem Beispiel
wie ist hier der Ablauf überhaupt. Warum wird hier nur die Funktion cachedFunc aufgerufen. Wie sieht es hier ausgeschrieben aus?
a = CacheDecorator(fak(n)) ?
Noch eine Frage zu der Vererbung, dieser Code hier
Die Klasse DahlManager erbt von der Klasse Manager. Der Aufruf von Basisklasse super(DahlManager, ..... das hängt bei mir. Wenn ich die Definition von Manager anschaue
hier wird wieder der constructor von der basisklasse aufgerufen, aber warum wird hier das Manager Objekt übergeben?
Danke kostonstyle
bei diesem Beispiel
Code: Alles auswählen
class CacheDecorator(object):
def __init__(self):
self.cache = {}
self.func = None
def cachedFunc(self, *args):
if args not in self.cache:
self.cache[args] = self.func(*args)
return self.cache[args]
def __call__(self, func):
self.func = func
return self.cachedFunc
@CacheDecorator()
def fak(n):
ergebnis = 1
for i in xrange(2, n+1):
ergebnis *= i
return ergebnis
print(fak(20))
print(fak(12))
print(fak(29))
print(fak(20))
print(fak(30))
a = CacheDecorator(fak(n)) ?
Noch eine Frage zu der Vererbung, dieser Code hier
Code: Alles auswählen
class DahlManager(models.Manager):
def get_query_set(self):
return super(DahlManager, self).get_query_set().filter(author='Roald Dahl')
Code: Alles auswählen
class Manager(object):
# Tracks each time a Manager instance is created. Used to retain order.
creation_counter = 0
def __init__(self):
super(Manager, self).__init__()
self._set_creation_counter()
self.model = None
self._inherited = False
Danke kostonstyle
Nein, wie cofi schon schrieb,kostonstyle hat geschrieben: wie ist hier der Ablauf überhaupt. Warum wird hier nur die Funktion cachedFunc aufgerufen. Wie sieht es hier ausgeschrieben aus?
a = CacheDecorator(fak(n)) ?
Code: Alles auswählen
@CacheDecorator()
def fac(n): pass
Code: Alles auswählen
def fac(n): pass
fac = CacheDecorator()(fac)
Bitte ein eigenes Thema aufmachen.Noch eine Frage zu der Vererbung, dieser Code hier
-
- User
- Beiträge: 148
- Registriert: Sonntag 2. November 2008, 12:13
Code: Alles auswählen
def fac(n): pass
fac = CacheDecorator()(fac)
Code: Alles auswählen
def fac(n): pass
fac = CacheDecorator(fac)
- birkenfeld
- Python-Forum Veteran
- Beiträge: 1603
- Registriert: Montag 20. März 2006, 15:29
- Wohnort: Die aufstrebende Universitätsstadt bei München
Achso, ich dachte, du meintest DasIhm sein SnippetDarii hat geschrieben:cachedFunc, aber ist nicht so wild, ich halte mich ja bei meinem Beispiel unten auch nicht dranbirkenfeld hat geschrieben:Was für Namenskonventionen?

Stimmt, deswegen gibts ja nonlocal in neueren VersionenFindest Dekorator-Funktionen wirklich immer lesbarer als Klassen? Wenn es der Lesbarkeit/Strukturierung dient, ist gegen eine Klasse nichts einzuwenden. Zumal manche Sachen ohne ``nonlocal`` wirklich „hacky“ werden, nur mit closures.Wie auch immer, hier eine Klasse zu verwenden, ist eindeutig Overkill. Genau dafür sind Closures doch da.

Ganz im Gegenteil; verteufeln tu ich Klassen nicht. Es ist nur bei manchen objektorientierten Sprachen so, dass man Klassen nicht nur dazu einsetzen darf, wozu sie da sind, sondern für alle anderen Fälle auch -- und da sind moderneIch kann mir nicht helfen, ich finde es mit Klasse lesbarer. Ich habe auch nicht behauptet, dass man *immer* Klassen verwenden *muss*, aber ich wollte der unterschwelligen Verteufelung von Klassen der man hier im Forum oft begegnet, mal entgegenwirken.Code: Alles auswählen
class cached(object): def __init__(self, func): self.cache = {} self.func = func def __call__(self, *args, **kwargs): cache_key = (args, tuple(kwargs.items())) if cache_key not in self.cache: self.cache[cache_key] = self.func(*args, **kwargs) return self.cache[cache_key] @cached def fac(n): if not n: return 1 return n*fac(n-1)

Da hast du recht, das war ein bisschen polemisch. Aber im Kern stimmt es, dass wer die Möglichkeiten, die man in Python ganz ohne eine Klasse zu schreiben hat, nicht kennt, nicht ausnutzt oder für unschön hält, was verpasst.Sei doch ehrlich, der Vergleich hinkt. Das wäre nur ein Fall von: Java-Kenntnisse unreflektiert auf Python übertragen."Gegen Klassen ist nichts einzuwenden" -- sagst du das auch dem Java-Programmierer, der eine Klasse "Main" schreibt, nur um eine "main"-Methode aufzurufen?
kostonstyle hat geschrieben:meinst du das soCode: Alles auswählen
def fac(n): pass fac = CacheDecorator()(fac)
aber von wo weiss der Compiler, das er die Methode cachedFunc aufrufen muss. Könntest du bitte nicht den Ablauf zeigen?Code: Alles auswählen
def fac(n): pass fac = CacheDecorator(fac)
Code: Alles auswählen
CacheDecorator()
Code: Alles auswählen
(fac)
MfG
HWK
Nein, ich meine es so, wie ich es geschrieben habe.kostonstyle hat geschrieben:meinst du das soCode: Alles auswählen
def fac(n): pass fac = CacheDecorator()(fac)
Code: Alles auswählen
def fac(n): pass fac = CacheDecorator(fac)
Probier es doch einfach selbst mal aus, notfalls probier die Zeile Buchstabe für Buchstabe aus.aber von wo weiss der Compiler, das er die Methode cachedFunc aufrufen muss. Könntest du bitte nicht den Ablauf zeigen?