Decorator Maker is working. What do you think?

R

Ron_Adam

Ok... it's works! :)

So what do you think?

Look at the last stacked example, it process the preprocess's first in
forward order, then does the postprocess's in reverse order. Which
might be usefull. Interesting in any case.

Making decorators with this class is a snap!

Any thoughts? Any improvements? Any bugs?

Cheers,
Ron_Adam


#---start---


class Decorator(object):
"""
Decorator - A base class to make decorators with.

self.function - the function decorated.
self.arglist - list of arguments of decorator
self.preprocess - over ride to preprocess function arguments.
self.postprocess - over ride to postprocess function
return value.
Example use:
class mydecorator(Decorate):
def self.preprocess(self, args):
# process args
return args
def self.postprocess(self, results):
# process results
return results

deco = mydecorator()

@deco
def function(args):
# function body
return args
"""
def __init__(self):
self.function = None
self.arglist = []
def __call__(self, *arg):
if len(arg) == 1:
arg = arg[0]
self.arglist.append(arg)
def _wrapper(*args):
pre_args = self.preprocess(*args)
if type(pre_args) is not tuple:
pre_args = (pre_args,)
result = self.function(*pre_args)
return self.postprocess(result)
if '<function ' in str(arg):
self.arglist = self.arglist[:-1]
self.function = arg
return _wrapper
return self

def preprocess(self, *args):
#
# Over ride this method.
#
return args

def postprocess(self, result):
#
# Over ride this method.
#
return result


#---1---
class decorator1(Decorator):
def preprocess(self, arg):
newarg = ""
n = 0
darg = list(self.arglist[0])
for a in list(arg):
newarg += a
newarg += darg[n]
n += 1
if n>=len(darg):
n = 0
return newarg
deco1 = decorator1()

@deco1('_-^-')
def test1(text):
return text
print test1('abcdefg')
# a_b-c^d-e_f-g^


#---2---
class decorator2(Decorator):
def postprocess(self, result):
result = result*1.0*self.arglist[0][0]/self.arglist[0][1]
return result
deco2 = decorator2()

@deco2(2,3)
def test2(a):
return a
print test2(7)
# 4.66666666667


#---3---
class decorator3(Decorator):
def preprocess(self, arg1, arg2):
arg1 *= 2
arg2 *= 2
return arg1, arg2
deco3 = decorator3()

@deco3
def test3(a,b):
return a,b
print test3(1,3)
# (2, 6)


#---4---
class decorator4(Decorator):
def postprocess(self, result):
result = int(result/self.arglist[0])
return result
deco4 = decorator4()

@deco4(2)
def test4(n1,n2,n3,n4,n5):
return n1+n2+n3+n4+n5
print test4(1,2,3,4,5)
# 7


#---5---
class decorator5(Decorator):
def preprocess(self, arg):
arg *= 2
print 'Preprocess:',self.arglist[0][0],arg
return arg
def postprocess(self, result):
result *= 2
print 'Postprocess:',self.arglist[0][0],result
return result
deco5a = decorator5()
deco5b = decorator5()
deco5c = decorator5()
deco5d = decorator5()
deco5e = decorator5()

@deco5a('a')
@deco5b('b')
@deco5c('c')
@deco5d('d')
@deco5e('e')
def test5(i):
return i

print test5(10)
# Preprocess: a 20
# Preprocess: b 40
# Preprocess: c 80
# Preprocess: d 160
# Preprocess: e 320
# Postprocess: e 640
# Postprocess: d 1280
# Postprocess: c 2560
# Postprocess: b 5120
# Postprocess: a 10240
# 10240

#---end---
 
R

Ron_Adam

Hi again, If anyone is reading this.

Fixed the endless loop when stacking the same decorator instance. You
can now reuse the same exact decorator object either in stacks or on
different functions with different arguments.

The only quirk left is if you stack the same decorator object, and
have arguments on some, but not others. The arguments get processed
first while preprocessing, and last when postprocessing. That
shouldn't be a problem though and is easy to avoid by using an empty
argument lists where they are needed.

Let me know if there are still any problems with it. I know someone
will find this useful.

Cheers,
Ron


(I left off the tests as they were getting to be quite long.)

#---start---

class Decorator(object):
"""
Decorator - A base class to make decorators with.

self.function - the function decorated.
self.arg - argument list passed by decorator
self.preprocess - over ride to preprocess function arguments
self.postprocess - over ride to postprocess function results
"""
def __init__(self):
self.function = None
self.arglist = []
self.arg = None
self._number = 0

def __call__(self, *arg):
if '<function ' in str(arg):
def _wrapper(*args):
try:
self.arg = self.arglist[self._number]
self._number += 1
except IndexError:
self.arg = None
pre_args = self.preprocess(*args)
if type(pre_args) is not tuple:
pre_args = (pre_args,)
result = _wrapper.function(*pre_args)
result = self.postprocess(result)
try:
self._number -= 1
self.arg = self.arglist[self._number-1]
if self._number == 0:
self.arglist = []
self.function = None
self.arg = None
except IndexError:
self.arg = None
return result
_wrapper.function = arg[0]
return _wrapper
self.arglist.append(arg)
return self

def preprocess(self, *args):
#
# Over ride this method.
#
return args

def postprocess(self, result):
#
# Over ride this method.
#
return result

#---end---
 
K

Kay Schluehr

Ron_Adam said:
Ok... it's works! :)

So what do you think?

Not much. As long as You do not present any nontrivial examples like
Guidos MultiMethod decorator or an implementation of the dispatching
"case" decorator I proposed that would benefit from factoring into pre-
and postprocessing the pattern has only limited use and worse it
suggests a misnomer: it obscures the semantics that is clearly
functional/OO not procedural.

Regards,
Kay
 
R

Ron_Adam

Not much. As long as You do not present any nontrivial examples like
Guidos MultiMethod decorator or an implementation of the dispatching
"case" decorator I proposed that would benefit from factoring into pre-
and postprocessing the pattern has only limited use and worse it
suggests a misnomer: it obscures the semantics that is clearly
functional/OO not procedural.

Regards,
Kay

No good points at all? :/

Are you saying I need to present a non trivial example such as Guido's
MultiMethod decorator, or the one you proposed?

If I'm not mistaken, there is a difference. Those axamples are
specific applications to solve specific problems using decorator
expressions. While what I'm attempting here is a general purpose
object in which many specific uses could more easily be built with.

What about commonly used trivial cases? As a whole are they not
non-trivial?

How is it limited?

I'm still not sure when, and what type of things, should and should
not be done with decorators.

It seems to me they may be good tools for validating inputs and
outputs, and for getting data on program performance. In those cases,
it would be good to be able to disable them when they aren't needed.

Another use is to redefine a decorator as needed to adapt a function
to a specific input or output. Is that what Guido's multimethod does?

And they might also be used as a way to change the behavior of a group
of related functions all at once at run time in order to save a lot of
code duplication.

I also think they could be abused easily and used when it would be
better to just use a class to do it in the first place.

Cheers,
Ron]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top