B
Bengt Richter
;-)
We have
@deco
def foo(): pass
as sugar (unless there's an uncaught exception in the decorator) for
def foo(): pass
foo = deco(foo)
The binding of a class name is similar, and class decorators would seem natural, i.e.,
@cdeco
class Foo: pass
for
class Foo: pass
Foo = cdeco(Foo)
What is happening is we are intercepting the binding of some object
and letting the decorator do something to the object before the binding occurs.
So why not
@deco
foo = lambdaass
equivalent to
foo = deco(lambdaass)
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'))
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]
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)
[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:
... print kw
... raise
... ... 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
orthogonal-musing-ly ;-)
Regards,
Bengt Richter
We have
@deco
def foo(): pass
as sugar (unless there's an uncaught exception in the decorator) for
def foo(): pass
foo = deco(foo)
The binding of a class name is similar, and class decorators would seem natural, i.e.,
@cdeco
class Foo: pass
for
class Foo: pass
Foo = cdeco(Foo)
What is happening is we are intercepting the binding of some object
and letting the decorator do something to the object before the binding occurs.
So why not
@deco
foo = lambdaass
equivalent to
foo = deco(lambdaass)
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'))
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]
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)
[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:
... print kw
... raise
... ... 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
orthogonal-musing-ly ;-)
Regards,
Bengt Richter