Seite 1 von 1

Decorater Klasse

Verfasst: Montag 26. September 2011, 08:54
von Gromix
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?

Re: Decorater Klasse

Verfasst: Montag 26. September 2011, 09:12
von 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.

Re: Decorater Klasse

Verfasst: Montag 26. September 2011, 09:46
von Gromix
@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.

Re: Decorater Klasse

Verfasst: Montag 26. September 2011, 11:56
von helduel
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

Re: Decorater Klasse

Verfasst: Montag 26. September 2011, 12:04
von Gromix
vielen vielen, dank!

das spart mir jetzt eine ganze menge arbeit :D