Are decorators really that different from metaclasses...

Paul Morrow pm_mon at yahoo.com
Tue Aug 31 14:20:53 CEST 2004


Steven Bethard wrote:
> Paul Morrow <pm_mon <at> yahoo.com> writes:
> 
>>Actually, these look like assignments to local *magic* variables.
>>There's the difference.  The double underscores before and after each
>>name loudly proclaims that these variables are not like 'normal'
>>variables.  They're special in some way.  That's a Python convention.
> 
> 
> Note that you're asking for __xxx__ variables to be assignments to the 
> function's attributes even though they're in the part of the function that 
> gets executed when the function is *called*. Let's look at what examples of 
> this behavior might look like for some different objects.
> 
> # in the part of a function that is executed when the function gets called
> def f():
>     __author__ = 'Steve'
> 
> # in the part of a class that is executed when the class gets called
> class S(object):
>     def __new__(cls):
>         __author__ = 'Steve'
> 
> # in the part of an object that is executed when the object gets called
> class T(object):
>     def __call__(self):
>         __author__ = 'Steve'
> 
> Note that the parallel I'm trying to draw here is that in each of these cases, 
> the __author__ is assigned to in the part of the definition that gets executed 
> when the object is *called*.  Thus f(), S(), and T()() all execute the code 
> block containing the __author__ assignment.  Presumably you wouldn't want the 
> __author__ statements to assign to the class or the object in the second two 
> examples?
> 

In all of your examples, the __author__ assignments apply to the object 
being defined.  In the first example, that's the function f.  In the 
second example that's the method __new__, and the method __call__ in the 
3rd example.

Note that this is true, /even in today's Python/.  Your intention behind 
each __author__ definition in your examples is *not* to create a local 
variable.  Your function/method (most likely) is not going to use 
__author__ when it executes.  Instead you are adding to the definition 
of the function/method.

What I'm wondering is whether we can stop thinking of assignments to 
magic attributes that immediately follow the docstring (if present) as 
something that gets executed when the function is called.  I think that 
we can.  I think that --- because of the names of these variables 
(author, version, features) --- they will obviously and intuitively be 
associated with the function's definition, not it's execution.  That's a 
point a lot of us have been forgetting here.  These variables don't 
sound like something the function would use in it's calculation.  So 
that, plus the fact that they are specially decorated (leading and 
trailing underscores), plus the fact that they immediately follow the 
docstring categorize them as part of the function's definition, not 
execution.

But why speculate.  Let's see if this is really going to be unclear in 
practice.  Ask someone who has never seen Python before which are the 
local variables in the following def.

    def circumference(diameter):
       """Calculate the diameter of a circle."""
       __author__ = 'Paul Morrow'
       __version__ = '0.1'
       pi = 3.14
       return pi * diameter


> Of course, what you really want is for these things to be assigned to in the 
> part that gets executed when the object is *defined*.  For a class, this is 
> clearly:
> 
> class S(object):
>     __author__ = 'Steve'
> 
> But what gets executed when a function is defined?  Just the def statement, 
> the binding of the function name to its body.  

And the binding of the __doc__ variable, if a docstring is present.


> To be consistent with classes 
> then, your assignment to __author__ should be *in* the def statement.  So what 
> you're suggesting, basically, is that the def statement should be extended to 
> include any __xxx__ assignments following the docstring. 
>

Yes.

> Extending the def statement is not unreasonable, but IMHO it should be clear 
> that the extensions to the def statement are part of that statement.  There's 
> nothing in current Python semantics that would suggest that any assignments in 
> a funcdef are part of the def statement. Note that even docstrings, which 
> could be reasonably argued to be part of the function definition, cannot be 
> included in the def statement by assignment:
> 
> 
>>>>def f():
> 
> ...     __doc__ = "f"
> ...
> 
>>>>print f.__doc__
> 
> None
> 
> Certainly __xxx__ variables are special in some way.  But are they special in 
> the way you want them to be?  

Not yet, /formally/.  But /in practice/ this is how they are used (to 
make meta statements about the thing being defined).

There's no need for a new syntax here.  We don't need more words in our 
language, or anything that makes our code less readable [*].


[*] Have you seen the decorator proposals?


> AFAICT, *assignment* to __xxx__ variables is 
> never what does the magic.  The magic is done when the Python interpreter 
> reads the *values* of those variables.  The variables continue to exist in 
> whatever namespace they were created in -- AFAICT, current Python __xxx__ 
> variable assignments never cause __xxx__ variables to change namespace.
> 

The assignments to __xxx__ variables (immediately following the 
docstring, if present) would occur in the namespace of the object 
(function/method) being defined.  The assignments would not cause them 
to change namespaces.

> I seems like you want to introduce a substantially new semantics to an already 
> existing syntax.  This creates ambiguity...  Ambiguity bad.  Bad, Ambiguitiy, 
> bad!  No biscuit! ;)
> 

I maintain that the author's intention behind these assignments is what 
we should focus on.  When we define a __xxx__ variable inside of a 
function def, we are (most likely) making a meta statement about the 
function.  We are not defining a local variable to be used later in the 
execution of the function.  So this proposal would not be changing the 
meaning of the __xxx__ assignments in practice.  It would merely be 
formalizing them.


Paul




More information about the Python-list mailing list