tweaking @decorator syntax

Bengt Richter bokr at oz.net
Thu Aug 5 17:01:20 EDT 2004


On 05 Aug 2004 14:17:25 +0000, John Marshall <John.Marshall at ec.gc.ca> wrote:

>On Thu, 2004-08-05 at 08:41, Sandy Norton wrote:
>> On 4 Aug 2004, Christopher T King wrote:
>>     
>> > Of course, I prefer the nested block idea better (either with a new
>> > keyword or new syntax), but I don't see those (especially the syntax one) 
>> > flying anytime soon.
>> 
>> I know further discussion of this topic is feeling futile, but one can only hope.
>> 
>> > Unless someone can come up with an idea everyone can agree on Real Soon 
>> > Now, I think the whole idea should be dropped and wait until 3.0.  We'll 
>> > have plenty of time to argue about it then.
>> 
>> Agreed.
>> 
>> > Sorry about the long rant, but it felt good to get that all off my chest.
>> 
>> Please, we need more rants like yours. Now if they could somehow 
>> collectively become a 'public outcry' (-;
>> 
>> I realize my hasty initial post didn't actually show the present 2.4 form, 
>> so I've included it and added your variations for the sake of comparison:
>> 
>
>With the current choice and the list of alternatives you gave,
>two things struck me about the location of the decorators
>in the current choice:
>    1) They seem to be in the wrong place with respect to
>       what they are affecting.
>    2) Can decorators easily be extended to apply to class
>       and module?
>
>Whether or not the @ or some other operator/keyword/etc. is
>used, what is more easily understandable/readable?
>-----
>class Klass:
>    def __init__(self, name):
>        self.name = name
>    
>    @staticmethod
>    def statmethod1(x):
>        return x
>    
>    @classmethod
>    def classmethod1(cls):
>        return cls
>    
>    @funcattrs(name='GvR', language='python')
>    @log(file='func.log')
>    def sayhello(self):
>        print 'hello python world'
>-----
>or
>-----
>class Klass:
>    def __init__(self, name):
>        self.name = name
>    
>    def statmethod1(x):
>	@staticmethod
>
>        return x
>    
>    def classmethod1(cls):
>	@classmethod
>
>        return cls
>    
>    def sayhello(self):
>	@funcattrs(name='GvR', language='python')
>	@log(file='func.log')
>
>        print 'hello python world'
>-----
>
>If the decorators are metadata, that may be extended to affect
>not only functions or methods, but classes, and modules(?), I would
>think that wherever a variable or function call would go that
>would affect the function, method, class, or module, is the
>right place for a decorator.
>
>In the alternative above, it _may_ be that the decorators would
>only be valid if they are located in specific locations, e.g.,
>before any non decorator (or comment, or __doc__ information)
>statements.
>

ISTM that this "decorating" business is a lot like what __metaclass__ does
for classes -- i.e., right at the end of a definition, the system looks for
a function to provide an optional extension of the definition process.

In the case of @some_name, 'some_name' is looked up somewhere (where? locals(),
nested scopes, globals(), globals()['__builtins__'].__dict__ ?) and the value is
supposed to be an appropriate decorator function.

I'm thinking of an alternative that doesn't seem to have been mentioned before,
namely a built-in class and a standard instance of it, containing a namespace which
would be used to find decorators, and which could be overridden and specialized etc.

Thus
    @A @B
    def foo():
        return whatever()

might look like

    metafunctions.add(foo=(A, B)) # could precede def anywhere you like for coding clarity
    def foo():
        return whatever()

and python function definition internals would be modified a la class/__metaclass__
functionality to find A and B via metafunctions (best design TBD ;-) and call as now
specified. Perhaps this could be unified with __metaclass__ and we could have, e.g.,
    metafunctions.add(MyClass=type) # turn classic to new style

Obviously you could define metafunctions to apply default decorators, e.g.
    metafunctions.setdefault(A,B,C)
    metafunctions.do_default_for('foo bar baz'.split())
    def foo(): ...
    def bar(): ...
    etc.
If you wanted to suppress metafunctions altogether, you could by convention shadow it
with a local None, i.e.,
    metafunctions = None
    ...
    del metafunctions # restore visibility of builtin


Or if you wanted a local copy to mess with in a particular module or program,
(it would probably not be good to allow .add easily to modify the builtin itself
unless there was a way to restore it reliably) you could perhaps write
    metafunctions = __builtins__.metafunctions.copy()

or you could define your own class
   class MyMetfun(Metafunctions):
       ...

   metafunctions = MyMetafun(...)
   metafunctions.my_handy_method(...)

etc.

The time of action might also be controlled in the future if someone finds it useful.
I.e., the time for examples above is right at the end of the function or class definition.
It might be interesting to be able to have metafunctions act at other times when certain
things are recognized also. What about at the time of instantiation of an exception, e.g.,
to inject debugging info or whatever?
    if __debug__:
        metafunctions = __import__('mymagic').Magic() #??
        metafunctions.add('MyException' ...)

You might need some way of defining patterns to recognize besides a plain name string.
Of course, instantiation of an exception is just a special case of instantiating a class,
so we could have metafunctions decorating object instances too, without modifying the source
of their classes. Hm, what about decorating module instances on import?

This and other possibilities would make possible factoring code in new ways, I suspect,
but as I just thought of it, I haven't really thought about it any further than you see here ;-)
Some possibilities would probably be dangerous, cryptic, and inadvisable in most circumstances.
We already have plenty of that. IMO the question is whether ordinary usage would help make for clearer
and more powerful expressions of coding ideas, and perhaps introduce useful elements for thinking
up those ideas.

I'm not for "tweaking @decorator syntax" -- I'm for saving '@' for something worthier
of its scarce-syntax-resource status.

Regards,
Bengt Richter



More information about the Python-list mailing list