473,761 Members | 10,276 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Decorator Base Class: Needs improvement.


Hi, Thanks again for all the helping me understand the details of
decorators.

I put together a class to create decorators that could make them a lot
easier to use.

It still has a few glitches in it that needs to be addressed.

(1) The test for the 'function' object needs to not test for a string
but an object type instead.

(2) If the same decorator instance is stacked, it will get locked in a
loop. But stacking different instances created from the same
decorator object works fine.

(3) It has trouble if a decorator has more than one argument.
But I think all of these things can be fixed. Would this be something
that could go in the builtins library? (After any issues are fixed
first of course.)

When these are stacked, they process all the prepossess's first, call
the decorator, then process all the postprocess's. It just worked out
that way, which was a nice surprise and makes this work a bit
different than the standard decorators.

Cheers,
Ron

#---start---

class Decorator(objec t):
"""
Decorator - A class to make decorators with.

self.function - name of function decorated.
self.arglist - arguments of decorator
self.preprocess - over ride to preprocess function arguments.
self.postproces s - over ride to postprocess function
return value.

Example use:
class mydecorator(Dec orate):
def self.preprocess (self, args):
# process args
return args
def self.postproces s(self, results):
# process results
return results

deco = mydecorator()

@deco
def function(args):
# function body
return args
"""
function = None
arglist = []
def __call__(self, arg):
self.arglist.ap pend(arg)
def _wrapper( args):
pre_args = self.preprocess (args)
result = self.function(p re_args)
return self.postproces s(result)
if 'function' in str(arg):
self.arglist = self.arglist[:-1]
self.function = arg
return _wrapper
return self
def preprocess(self , args):
return args
def postprocess(sel f, result):
return result

class mydecorator(Dec orater):
def preprocess(self , args):
args = 2*args
return args
def postprocess(sel f, args):
args = args.upper()
args = args + str(self.arglis t[0])
return args
deco = mydecorator()

@deco('xyz')
def foo(text):
return text

print foo('abc')
#---end---
Jul 18 '05 #1
22 2237

Ok, that post may have a few(dozen?) problems in it. I got glitched
by idles not clearing variables between runs, so it worked for me
because it was getting values from a previous run.

This should work better, fixed a few things, too.

The decorators can now take more than one argument.
The function and arguments lists initialize correctly now.

It doesn't work with functions with more than one variable. It seems
tuples don't unpack when given to a function as an argument. Any way
to force it?
class Decorator(objec t):
"""
Decorator - A base class to make decorators with.

self.function - name of function decorated.
self.arglist - arguments of decorator
self.preprocess - over ride to preprocess function arguments.
self.postproces s - over ride to postprocess function
return value.

Example use:
class mydecorator(Dec orate):
def self.preprocess (self, args):
# process args
return args
def self.postproces s(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.ap pend(arg)
def _wrapper( *args):
if len(args) == 1:
args = args[0]
pre_args = self.preprocess (args)
result = self.function(p re_args)
return self.postproces s(result)
if 'function' in str(arg):
self.arglist = self.arglist[:-1]
self.function = arg
return _wrapper
return self
def preprocess(self , args):
return args
def postprocess(sel f, result):
return result
#---3---
class mydecorator(Dec orator):
def preprocess(self , args):
args = 2*args
return args
def postprocess(sel f, args):
args = args.upper()
args = args + str(self.arglis t[0])
return args
deco = mydecorator()

@deco('xyz')
def foo(text):
return text
print foo('abc')
#---2---
class decorator2(Deco rator):
def preprocess(self , args):
return args+sum(self.a rglist[0])
def postprocess(sel f, args):
return args
deco2 = decorator2()

@deco2(1,2)
def foo(a):
return a
print foo(1)

# This one doesn't work yet.
#---3---
class decorator3(Deco rator):
pass
deco3 = decorator3()

@deco3
def foo(a,b):
return a,b
print foo(1,3)
Jul 18 '05 #2
Ron_Adam wrote:
Ok, that post may have a few(dozen?) problems in it. I got glitched
by idles not clearing variables between runs, so it worked for me
because it was getting values from a previous run.

This should work better, fixed a few things, too.

The decorators can now take more than one argument.
The function and arguments lists initialize correctly now.
Ron:

I've followed your attempts to understand decorators with interest, and
have seen you engage in conversation with many luminaries of the Python
community, so I hesitate at this point to interject my own remarks.

In a spirit of helpfulness, however, I have to ask whether your
understanding of decorators is different from mine because you don't
understand them or because I don't.

You have several times mentioned the possibility of a decorator taking
more than one argument, but in my understanding of decorators this just
wouldn't make sense. A decorator should (shouldn't it) take precisely
one argument (a function or a method) and return precisely one value (a
decorated function or method).
It doesn't work with functions with more than one variable. It seems
tuples don't unpack when given to a function as an argument. Any way
to force it?
class Decorator(objec t):

[...]

Perhaps we need to get back to basics?

Do you understand what I mean when I say a decorator should take one
function as its argument and it should return a function?

regards
Steve
--
Steve Holden +1 703 861 4237 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/
Python Web Programming http://pydish.holdenweb.com/

Jul 18 '05 #3
Steve Holden wrote:
You have several times mentioned the possibility of a decorator taking more than one argument, but in my understanding of decorators this just wouldn't make sense. A decorator should (shouldn't it) take precisely one argument (a function or a method) and return precisely one value (a decorated function or method).


Yes. I think this sould be fixed into the minds of the people exacly
this way You state it:

When writing

@decorator(x,y)
def f():
....

not the so called "decorator" function but decorator(x,y) is the
decorating function and decorator(x,y) is nothing but a callable object
that takes f as parameter. A little correcture of Your statement: it is
NOT nessacary that a function or method will be returned from a
decorator.

def decorator(x,y):
def inner(func):
return x+y
return inner

@decorator(1,2)
def f():pass
f

3

This is perfectly valid allthough not very usefull ;)

Regards,
Kay

Jul 18 '05 #4
On 5 Apr 2005 00:54:25 -0700, "Kay Schluehr" <ka**********@g mx.net> wrote:
Steve Holden wrote:
You have several times mentioned the possibility of a decoratortaking
more than one argument, but in my understanding of decorators this

just
wouldn't make sense. A decorator should (shouldn't it) take precisely

one argument (a function or a method) and return precisely one value

(a
decorated function or method).

I agree from an English language point of view. I.e., a verber is
something that does the verbing, so a decorator ought to be the thing
that does the decorating, which is the function/callable(s) resulting
on stack from the evaluation of the @-line.

In the case of a single @deco name, the evaluation is trivial, and
the difference between the @-expression and the resulting callable
might be overlooked. Full-fledged general expressions after the '@'
are for some reason disallowed, but it is handy to allow attribute
access and calling in the syntax, so the relevant Grammar rules are:

From the 2.4 Grammar, the key part seems to be

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
funcdef: [decorators] 'def' NAME parameters ':' suite

and further on

dotted_name: NAME ('.' NAME)*

So the Python Grammar's name for the @-expression is just plain "decorator"
which conflicts with my English-based reading of the word ;-/

So it appears the intent is to call the entire @-line the "decorator"
and I guess to have a name for what evaluating the @-line returns on the
stack, we could call it the "decorating callable" since it is what takes
the function parameter as its first parameter and decorates the function
and returns the decorated function.

But I don't like it, English-wise. I would rather call the @-line
the "decorator expression" and what it evaluates to the "decorator. "

Can we change the grammar with s/decorator/decorator_expr/ ?
Yes. I think this sould be fixed into the minds of the people exacly
this way You state it: I think we may be agreeing in principle but with different words ;-)
When writing

@decorator(x,y )
def f():
....

not the so called "decorator" function but decorator(x,y) is the ^--(the result of evaluating)decorating function and decorator(x,y) is nothing but a callable object ^--(the result of evaluating)that takes f as parameter. A little correcture of Your statement: it is
NOT nessacary that a function or method will be returned from a
decorator.
Yes, in fact it could even perversely be colluding with a known succeeding
decorator callable to pass info strangely, doing strange things, e.g.,
trick = ['spam', 'eggs']
def choose_name(tup ): ... nx, f = tup
... f.func_name = trick[nx]
... return f
... def namedeco(nx=1): ... return lambda f, nx=nx:(nx, f)
... @choose_name ... @namedeco()
... def foo(): pass
... foo <function eggs at 0x02EE8E64> @choose_name ... @namedeco(0)
... def foo(): pass
... foo <function spam at 0x02EE8DF4>

I.e., namedeco evaluates to the lambda as decorator function,
and that passes a perverse (nx, f) tuple on to choose_name, instead
of a normal f.

def decorator(x,y):
def inner(func):
return x+y
return inner

@decorator(1,2 )
def f():pass
f

3

This is perfectly valid allthough not very usefull ;)


Perhaps even less useful, the final decorator can return something
arbitrary, as only the name in the def matters at that point in
the execution (as a binding target name), so:
def dumbdeco(f): return 'something dumb' ... @dumbdeco ... def foo(): pass
... foo 'something dumb'

Hm, maybe some use ...
def keydeco(name): ... return lambda f: (name, f)
... @keydeco('pooh_ foo') ... def foo(): pass
... @keydeco('tigge r_bar') ... def bar(): pass
... dict([foo, bar])

{'pooh_foo': <function foo at 0x02EE8DBC>, 'tigger_bar': <function bar at 0x02EE8DF4>}

.... nah ;-)
Anyway, I think a different name for what comes after the "@" and the
callable that that (very limited) expression is supposed to return
would clarify things. My conceptual model is

@decorator_expr ession # => decorator
def decorating_targ et(...):
...

Regards,
Bengt Richter
Jul 18 '05 #5
Bengt Richter wrote:
From the 2.4 Grammar, the key part seems to be

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
funcdef: [decorators] 'def' NAME parameters ':' suite

and further on

dotted_name: NAME ('.' NAME)*

So the Python Grammar's name for the @-expression is just plain "decorator" which conflicts with my English-based reading of the word ;-/


What about playing with the words decorator/decoration? The allegoric
meaning of the decorator

def deco(f):
pass

would be: f is "vanishing under decoration" - all is vanity.

In the example deco would be both a decorator and a decoration. In
other examples deco were a decorator and deco(x,y) the decoration.

Regards,
Kay

Jul 18 '05 #6
Bengt Richter wrote:
From the 2.4 Grammar, the key part seems to be

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
funcdef: [decorators] 'def' NAME parameters ':' suite

and further on

dotted_name: NAME ('.' NAME)*

So the Python Grammar's name for the @-expression is just plain "decorator" which conflicts with my English-based reading of the word ;-/


What about playing with the words decorator/decoration? The allegoric
meaning of the decorator

def deco(f):
pass

would be: f is "vanishing under decoration" - all is vanity.

In the example deco would be both a decorator and a decoration. In
other cases deco were a decorator and deco(x,y) the decoration.

Regards,
Kay

Jul 18 '05 #7
On Tue, 05 Apr 2005 02:55:35 -0400, Steve Holden <st***@holdenwe b.com>
wrote:
Ron_Adam wrote:
Ok, that post may have a few(dozen?) problems in it. I got glitched
by idles not clearing variables between runs, so it worked for me
because it was getting values from a previous run.

This should work better, fixed a few things, too.

The decorators can now take more than one argument.
The function and arguments lists initialize correctly now.
Ron:

I've followed your attempts to understand decorators with interest, and
have seen you engage in conversation with many luminaries of the Python
community, so I hesitate at this point to interject my own remarks.


I don't mind. It might help me communicate my ideas better.
In a spirit of helpfulness, however, I have to ask whether your
understandin g of decorators is different from mine because you don't
understand them or because I don't.
Or it's just a communication problem, and we both understand.
Communicating is not my strongest point. But I am always willing to
clarify something I say.
You have several times mentioned the possibility of a decorator taking
more than one argument, but in my understanding of decorators this just
wouldn't make sense. A decorator should (shouldn't it) take precisely
one argument (a function or a method) and return precisely one value (a
decorated function or method).
It doesn't work with functions with more than one variable. It seems
tuples don't unpack when given to a function as an argument. Any way
to force it?
What I was referring to is the case:

@decorator(x,y, z)

As being a decorator expression with more than one argument. and not:

@decorator(x)(y )

This would give a syntax error if you tried it.
@d1(1)(2)
SyntaxError: invalid syntax

The problem I had with tuple unpacking had nothing to do with
decorators. I was referring to a function within the class, and I
needed to be consistent with my use of tuples as arguments to
functions and the use of the '*' indicator.
Do you understand what I mean when I say a decorator should take one
function as its argument and it should return a function?

regards
Steve


Hope this clarifies things a bit.

Cheers,
Ron
Jul 18 '05 #8
Ron_Adam wrote:
What I was referring to is the case:
@decorator(x,y, z)
As being a decorator expression with more than one argument. But, we generally say this is a call to a function named decorator
that returns a decorator. If you called it:
@make_decorator (x,y)
def .....
We'd be sure we were all on the same page.

How about this as an example:

def tweakdoc(name):
def decorator(funct ion):
function.__doc_ _ = 'Tweak(%s) %r' % (name, function.__doc_ _)
return function
return decorator

What is confusing us about what you write is that you are referring to
tweakdoc as a decorator, when it is a function returning a decorator.
and not:
@decorator(x)(y )


This is only prevented by syntax (probably a good idea, otherwise
we would see some very complicated expressions before function
declarations).

--Scott David Daniels
Sc***********@A cm.Org
Jul 18 '05 #9
On Tue, 05 Apr 2005 14:32:59 -0700, Scott David Daniels
<Sc***********@ Acm.Org> wrote:
Ron_Adam wrote:
What I was referring to is the case:
@decorator(x,y, z)
As being a decorator expression with more than one argument.But, we generally say this is a call to a function named decorator
that returns a decorator. If you called it:
@make_decorator (x,y)
def .....
We'd be sure we were all on the same page.


Good point, I agree. :)

Or alternatively
@call_decorator (x,y)

Using either one would be good practice.
How about this as an example:

def tweakdoc(name):
def decorator(funct ion):
function.__doc_ _ = 'Tweak(%s) %r' % (name, function.__doc_ _)
return function
return decorator

What is confusing us about what you write is that you are referring to
tweakdoc as a decorator, when it is a function returning a decorator.


Bengt Richter is also pointing out there is an inconsistency in
Pythons documents in the use of decorator. I've been trying to start
referring to the "@___" as the decorator-exression, but that still
doesn't quite describe what it does either. Decorarator-caller might
be better. Then the decorator-function as the part that defines the
decorated-function.

Another alternative is to call the entire process what it is,
function-wrapping. Then the "@____" statement would be the
wrapper-caller, which calls the wrapper-function, which defines the
wrapped-function. That's much more descriptive to me.

If we do that then we could agree to use decorator as a general term
to describe a function as decorated. Meaning it is wrapped and get
away from the decorator/decoratoree discussions. But I think that the
terminology has been hashed out quite a bit before, so I don't expect
it to change. I'll just have to try to be clearer in how I discuss
it.
and not:
@decorator(x)(y )


This is only prevented by syntax (probably a good idea, otherwise
we would see some very complicated expressions before function
declarations ).

--Scott David Daniels
Sc***********@ Acm.Org


And this isn't allowed either, although it represents more closely the
nesting that takes place when decorator-expressions are stacked.

@make_deco1
@make_deco2
@make_deco3
def function1(n):
n+=1
return n
This is allowed, but its not pretty.

@make_deco1
@ make_deco2
@ make_deco3
def function1(n):
n+=1
return n
Cheers,
Ron
Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
1501
by: lcaamano | last post by:
We have a tracing decorator that automatically logs enter/exits to/from functions and methods and it also figures out by itself the function call arguments values and the class or module the function/method is defined on. Finding the name of the class where the method we just entered was defined in is a bit tricky. Here's a snippet of the test code: class Base: @tracelevel(1)
5
1817
by: Doug | last post by:
I am looking at using the decorator pattern to create a rudimentary stored proc generator but am unsure about something. For each class that identifies a part of the stored proc, what if I want to add a value dynamically. I'm including some code to show what I mean. This is real basic on what I want to do: using System; namespace ClassLibrary1 {
1
1532
by: Doug | last post by:
I am looking at using the decorator pattern to create a rudimentary stored proc generator but am unsure about something. For each class that identifies a part of the stored proc, what if I want to add a value dynamically. I'm including some code to show what I mean. This is real basic on what I want to do: using System; namespace ClassLibrary1 {
9
1439
by: Raymond Hettinger | last post by:
I had an idea but no time to think it through. Perhaps the under-under name mangling trick can be replaced (in Py3.0) with a suitably designed decorator. Your challenge is to write the decorator. Any trick in the book (metaclasses, descriptors, etc) is fair game. Raymond -------- how we currently localize method access with name mangling
9
3458
by: Christian Hackl | last post by:
Hi! I've got a design question related to the combination of the NVI idiom (non-virtual interfaces, ) and popular object-oriented patterns such as Proxy or Decorator, i.e. those which have the basic idea of deriving from a base class and delegating to an object of it at the same time. My problem is that I cannot seem to combine those two techniques in a flawless way. For a very simple, non real life example (for which I shall omit...
4
2472
by: thomas.karolski | last post by:
Hi, I would like to create a Decorator metaclass, which automatically turns a class which inherits from the "Decorator" type into a decorator. A decorator in this case, is simply a class which has all of its decorator implementation inside a decorator() method. Every other attribute access is being proxied to decorator().getParent(). Here's my attempt: -------------------------------------------------------
11
1718
by: George Sakkis | last post by:
I have a situation where one class can be customized with several orthogonal options. Currently this is implemented with (multiple) inheritance but this leads to combinatorial explosion of subclasses as more orthogonal features are added. Naturally, the decorator pattern comes to mind (not to be confused with the the Python meaning of the term "decorator"). However, there is a twist. In the standard decorator pattern, the decorator...
8
2887
by: Chris Forone | last post by:
hello group, is there a possibility to implement the decorator-pattern without new/delete (nor smartpt)? if not, how to ensure correct deletion of the objects? thanks & hand, chris
8
2738
by: Bryan | last post by:
I want my business objects to be able to do this: class Person(base): def __init__(self): self.name = None @base.validator def validate_name(self): if not self.name: return
0
9531
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9957
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9905
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9775
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8780
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7332
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6609
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
1
3881
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
2752
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.