Are decorators really that different from metaclasses...

Paul Morrow pm_mon at yahoo.com
Wed Sep 1 19:40:13 EDT 2004


Hallvard B Furuseth wrote:
> Paul Morrow wrote:
> 
>>Hallvard B Furuseth wrote:
>>
>>>Paul Morrow wrote:
>>>
>>>>I believe that we should think of assignments to __xxx__ attributes as 
>>>>not being part of the function's body, but instead part of its 
>>>>declaration, just as we do with its docstring.
>>>>
>>>>   def circum(diameter):
>>>>       """This describe's foo."""
>>>>       __author__ = 'Paul Morrow'
>>>>       __version__ = '0.1'
>>>>       __features__ = synchronized, memoized
>>>
>>>
>>>I really, really don't like this idea.  Assignment in Python has quite
>>>enough pitfalls already.  Please don't make it worse.  If it looks like
>>>an assignment to a local variable, it should be an assignment to a local
>>>variable.  
>>
>>Actually, these look like assignments to local *magic* variables.
>>There's the difference.
> 
> 
> No, that's not the difference.  It's still different from how magic
> variables behave in all other places.  (Class bodies, module bodies,
> object attributes).  The difference is that magic variables in this
> particular localtion is actually parsed differently from use of
> variables other places, so the '=' operator (and what other operators?)
> means something else.
> 

Only the '=' operator, no others.

They [*] would be parsed when the function definition is processed and
then assigned to the function.  Just as in the following, they are
parsed when the class definition is processed and then assigned to the
class.  Nothing special happens in either case.  Just names being added
to a namespace.

    class Circle(Shape):
        """This describe's Circle."""
        __author__ = 'Paul Morrow'
        __version__ = '0.1'
        __metaclass__ = M


[*] the magic variables


> 
>>The double underscores before and after each name loudly proclaims
>>that these variables are not like 'normal' variables.  They're special
>>in some way.
> 
> 
> No other magic variables are that special.  They all behave normally _as
> variables_.  Other parts of Python react to them being set or reset, the
> very variable assigments are quite normal.  Except for the name mangling
> of __*__ instance variables, but that is a lot smaller exception than
> changing the namespace of the assignment operator and the time at which
> that operator is executed.
> 

Assignments that pertain to the definition of something are processed
when the thing is defined.  When used as I've been describing here,
__xxx__ variables pertain to the definition of the function.  Therefore,
they are processed when the function is defined.  That's the *right*
time to process them.



> 
>>>If we are going to invent a syntax for declaring function
>>>attributes inside the function, why confuse the issue by making it look
>>>like it does something else?
>>
>>Because 1) adding new syntax should be resisted as much as possible
>>(IMO),
> 
> 
> If one can extend old syntax in an intuitive way, it's fine to reuse old
> syntax.  When you extend old syntax to mean something counterintuitive,
> it's far better to find a new syntax.  And while it may seem intuitive
> to you, you may have noticed that it seems counterintuitive to a lot of
> others.
> 

I have no idea how the lurkers feel about this.  Maybe you are right.
Maybe this only makes sense to me.

> 
>>and 2) this style has parallels in both class definitions and 
>>module definitions.
> 
> 
> It parallels them as long as you don't think of how it works.  Once you
> do think of how it works, it's completely different.  And you get a lot
> of subtle differences to confuse the issue.
> 

You need to show me the subtle differences.  I'm not aware of any (that
matter).

> 
>>Compare this class statement with the function def 
>>above.
>>
>>     class Oval(Circle):
>>         """This describe's Oval."""
>>         __author__ = 'Paul Morrow'
>>         __version__ = '0.1'
>>         __metaclass__ = M
> 
> 
> Yes, I can compare that.  It's fine in a class body, which is executed
> when the class definition is executed.  When I see it in a function
> definition, I see a strange use of the assignment operator, which is
> normally a 'run-time' operator, in a place where it not being executed
> at run-time.
> 

It's also a 'definition-time' operator, as it often appears in class and
module definitions.  So why not be consistent and let it appear in
function definitions too?  What is so outrageous about this idea? On the
'strange-meter', does it rank as high as docstrings or meaningful
indentation?


> You keep displaying such examples as if they should make your point
> self-evident.  Already several people have pointed out that they don't
> see it at self-evident.  That might give you a clue that it isn't
> self-evident.
>

Again, I have no idea if I'm alone on this.  A few have suggested that
they somewhat agree, but there's not been much support beyond that.

> 
>>>It's true that it makes it look more like what __*__ attribute
>>>assignment in class bodies does, but the simple fact is that class
>>>bodies are executed when the class statement is executed, and function
>>>bodies are not executed when the def statement is executed.  Now you
>>>want part of the function bodies to be executed at def time, and part at
>>>call time.
>>
>>Maybe we just need to be clear as to which lines under the def statement
>>constitute the function's /body/.
> 
> 
> That's perfectly clear without your change.  Your change is confusing
> the issue, by also using an operator which one (well, at least many of
> us - not you, obviously) expects to be executed in the function body.
> 

We change the definition of where the function body starts, to exclude
any __xxx__ assignments immediately following the docstring.  Then the
'=' operator has definition-time semantics, not run-time.


> 
>>The function's docstring gets
>>assigned during processing of the def statement, therefore the docstring
>>is apparently not part of the function body;
> 
> 
> The function's doc string doesn't look like a statement, and even if it
> one thinks it is one (which documentation handling somehow picks out
> specially) it would be a no-op inside the function, so there is nothing
> confusing about it.
> 
> BTW, I was all for having the function body extend further down - my
> first decorator choice (before J2) would have been the
>   def foo(...):
>      ...decorators and doc string...
>   some_keyword:
>      ...body...
> 
> syntax.  Like you point out about __*__ assigments it stands out, but
> it's even clearer, but it doesn't look like it would normally
> dosomething else, so the uninitiated will have far less reason to wonder
> what kind of voodoo is going on to make it do what it does.
> 

All of the suggestions I've seen like that one have the section keyword
at the same level of indentation as the def keyword, which is wrong
(IMO).  There is no precedent for that in Python.  We are defining
something; every statement related to that definition should be indented
farther to the right than the def statement (IMO).

But this is all moot I guess.  Guido has apparently already made up his 
mind on the decorator syntax.  So I guess I'm done with this subject [*].

Thanks for your feedback.

Paul

[*] for now :-)




More information about the Python-list mailing list