decorators as generalized pre-binding hooks
Ron Adam
rrr at ronadam.com
Sun Jul 10 01:35:01 EDT 2005
Bengt Richter wrote:
> ;-)
> We have
Have we?
Looks like not a lot of interested takers so far.
But I'll bite. ;-)
<clip intro>
> So why not
>
> @deco
> foo = lambda:pass
> equivalent to
> foo = deco(lambda:pass)
>
> and from there,
> @deco
> <left-hand-side> = <right-hand-side>
> being equivalent to
> <left-hand-side> = deco(<right-hand-side>)
>
> e.g.,
> @range_check(1,5)
> a = 42
> for
> a = range_check(1,5)(42)
>
> or
> @default_value(42)
> b = c.e['f']('g')
> for
> b = default_value(42)(c.e['f']('g'))
So far they are fairly equivalent. So there's not really any advantage
over the equivalent inline function. But I think I see what you are
going towards. Decorators currently must be used when a function is
defined. This option attempts to makes them more dynamic so that they
can be used where and when they are needed.
How about if you make it optional too?
if keep_log:
@log_of_interesting_values
b = get_value(c,d):
Or...
@@keeplog log_of_interesting_values # if keeplog decorate.
b = get_value(c,d)
Just a thought.
> Hm, binding-intercept-decoration could be sugar for catching exceptions too,
> and passing them to the decorator, e.g., the above could be sugar for
>
> try:
> b = default_value(42)(c.e['f']('g'))
> except Exception, e:
> b = default_value(__exception__=e) # so decorator can check
> # and either return a value or just re-raise with raise [Note 1]
I'm not sure I follow this one.. Well I do a little. Looks like it might
be going the direction of with statements, but only applied to a single
expression instead of a block or suite.
> This might be useful for plain old function decorators too, if you wanted the decorator
> to define the policy for substituting something if e.g. a default argument evaluation
> throws and exception. Thus
>
> @deco
> def foo(x=a/b): pass # e.g., what if b==0?
> as
> try:
> def foo(x=a/b): pass # e.g., what if b==0?
> foo = deco(foo)
> except Exception, e:
> if not deco.func_code.co_flags&0x08: raise #avoid mysterious unexpected keyword TypeError
> foo = deco(__exception__=e)
Wouldn't this one work now?
> [Note 1:]
> Interestingly raise doesn't seem to have to be in the same frame or down-stack, so a decorator
> called as above could re-raise:
>
> >>> def deco(**kw):
> ... print kw
> ... raise
> ...
> >>> try: 1/0
> ... except Exception, e: deco(__exception__=e)
> ...
> {'__exception__': <exceptions.ZeroDivisionError instance at 0x02EF190C>}
> Traceback (most recent call last):
> File "<stdin>", line 2, in ?
> File "<stdin>", line 1, in ?
> ZeroDivisionError: integer division or modulo by zero
Interestin.
When it comes to decorators, and now the with statements, I can't help
but feel that there's some sort of underlying concept that would work
better. It has to do with generalizing flow control in a dynamic way
relative to an associated block.
One thought is to be able to use a place holder in an expression list to
tell a statement when to do the following block of code.
I'll use 'do' here... since it's currently unused and use @@@ as the
place holder.
(These are *NOT* thought out that far yet, I know... just trying to
show a direction that might be possible.)
do f=open(filename); @@@; f.close(): # do the block where @@@ is.
for line in f:
print line,
print
And an alternate version similar to a "with" statement.
try f=open(filename); @@@; finally f.close():
for line if f:
print line,
print
Maybe the exception could be held until after the try line is complete?
The place holder idea might be useful for decorating as well. But I'm
not sure how the function name and arguemtns would get passed to it.
do deco(@@@):
def foo():
pass
or maybe it would need to be...
do f=@@@, deco(f):
def foo()
pass
As I said, it still needs some thinking.. ;-)
Maybe leaving off the colon would use the following line without
indenting as per your example?
do deco(@@@)
b = 42
It doesn't quite work this way I think. Possibly having a couple of
different types of place holder symbols which alter the behavior might work?
do deco($$$) # $$$ intercept name binding operation?
b = 42
Well, it may need to be a bit (or a lot) of changing. But the idea of
controlling flow with a place holder symbol might be a way to generalize
some of the concepts that have been floating around into one tool.
I like the place holders because I think they make the code much more
explicit and they are more flexible because you can put them where you
need them.
> orthogonal-musing-ly ;-)
"Orthogonal is an unusual computer language in which your program flow
can go sideways. In actuality in can go in just about any direction you
could want."
http://www.muppetlabs.com/~breadbox/orth/
;-)
Cheers,
Ron
> Regards,
> Bengt Richter
More information about the Python-list
mailing list