Decorater Klasse

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
Gromix
User
Beiträge: 3
Registriert: Montag 26. September 2011, 08:48

Hallo erst mal.

Ich habe folgendes Problem:

Code: Alles auswählen

from collections import deque

class Decorator :
	def __init__(self, func ):
		self._func = func
		self.queue = deque()
		
	def __call__( self, *args ) :
		self.queue.append(args)
		
	def process(self) :
		args = self.queue.popleft()
		print args
		self._func( *args )
		
class Clss :
	@Decorator
	def do_stuff(self, x ) :
		# do stuff with x
		pass
				
clss = Clss()

clss.do_stuff(2) # -> TypeError: do_stuff() takes exactly 2 arguments (1 given)

clss.do_stuff.process()
Ich möchte meinen Decorator gerne als Klasse haben, aber wenn man diesen dann auf eine andere Klassenmethode anwendet, denn geht das 'self' der aufrufenden Klasse verloren?

Dieses Problem tritt nicht auf wenn man Funktionen als Decorator benutzt.

Hat jemand eine Idee wie man das trotzdem hinbekommt?
Zuletzt geändert von Gromix am Montag 26. September 2011, 09:46, insgesamt 2-mal geändert.
BlackJack

@Gromix: Ohne es jetzt ausprobiert zu haben, aber Du würdest genau die selbe Ausnahme bekommen wenn Du denn Dekorator hier weg lässt. Die Methode erwartet ein Argument und Du gibst da beim Aufruf keines an! Ich würde mal sagen das `self` wird „automatisch” übergeben, aber die Methode erwartet ja auch noch einen Wert für das `x`. Da übergibst Du aber nichts → Ausnahme.
Gromix
User
Beiträge: 3
Registriert: Montag 26. September 2011, 08:48

@BlackJack Der Code oben ist nur da um das Problem zu veranschaulichen. und self, wird nicht übergeben!

Der Output vom lauf fähigen Beispiel sieht aus:

Code: Alles auswählen

(2,)
Traceback (most recent call last):
  File "C:\Dokumente und Einstellungen\Simon\Eigene Dateien\jython\decorator.py", line 26, in <module>
    clss.do_stuff.process()
  File "C:\Dokumente und Einstellungen\Simon\Eigene Dateien\jython\decorator.py", line 14, in process
    self._func( *args )
TypeError: do_stuff() takes exactly 2 arguments (1 given)
Wie man sieht wird das self, nicht als parameter an den Decorator.__call__ übergeben.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Moin!

Hier wurde einfach vergessen, dass beim Instanzieren einer Klasse deren Methoden an die Instanz gebunden werden. Das geschieht mit diesem Decorator aber nicht (darum muss man sich nämlich selber kümmern). Funktionen/Methoden sind Deskriptoren, haben also eine __get__-Methode, die beim Binden an eine Instanz aufgerufen wird und die gebundene Methode zurück gibt. Das muss man im Decorator implementieren. So funktioniert es:

Code: Alles auswählen

from collections import deque

class Decorator(object):
   def __init__(self, func ):
      self._func = func
      self.queue = deque()

   def __get__(self, instance, cls):
      self._func = self._func.__get__(instance, cls)
      return self

   def __call__(self, *args ) :
      self.queue.append(args)

   def process(self) :
      args = self.queue.popleft()
      print args
      self._func( *args )


class Clss(object):
   @Decorator
   def do_stuff(self, x ) :
      # do stuff with x
      pass


clss = Clss()
clss.do_stuff(2)
clss.do_stuff.process()
Gruß,
Manuel
Gromix
User
Beiträge: 3
Registriert: Montag 26. September 2011, 08:48

vielen vielen, dank!

das spart mir jetzt eine ganze menge arbeit :D
Antworten