Are decorators really that different from metaclasses...

Hallvard B Furuseth h.b.furuseth at usit.uio.no
Tue Aug 31 18:01:29 EDT 2004


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.

> 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.

>> 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.

> 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.

> 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.

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.

>> 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.

> 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.

> So why not have assignments to __xxx__
> variables also be part of the function's declaration.

Because it looks confusing.

> The distinctive appearance of these names helps remind us that they
> have special semantics.

And if we use another syntax, we won't need to be reminded about
anything, and there is nothing to be confused about.

>> __*__ assigments in class bodies can look a little confusing if you
>> don't think of how class declarations work, but it's perfectly simple
>> once you think of how they do work: (...)
> 
> Perhaps its just my experience with declarative programming languages,
> but I prefer thinking of __xxx__ assignments in a class as setting
> 'properties' of the class.  (...)

I prefer to try to think a bit like the language I'm using does.
At least for me it makes it far easier to keep things straight.

-- 
Hallvard



More information about the Python-list mailing list