__metaclass__ and __author__ are already decorators

P

Paul Morrow

Thinking about decorators, and looking at what we are already doing in
our Python code, it seems that __metaclass__, __author__, __version__,
etc. are all examples of decorators. So we already have a decorator
syntax. What is the compelling reason to invent a new one? And if we
do, what's to become of the old one?

Here's my take on this. We have two kinds of decorators: those that
are informational only (like __author__ and __version__), and those
which have side-effects, i.e. those that actually *do* something (like
__metaclass__).

class Foo:
""" This describes the Foo class as normal. """
__metaclass__ = M
__author__ = 'Paul Morrow'
__version__ = '0.1'
__automethods__ = True


def baz(self, a, b):
""" This describes the baz method. """
__synchronized__ = True
__returns__ = None
__author__ = 'Neville Shunt'
# body of baz goes here...

There, that looks pretty clear and pythonic. Now how to define the
decorators.

def metaclass(decoratedClass, subType):
""" This describes the 'metaclass' decorator. """
__decorator__ = True
__version__ = '1.9'
# perform the metaclass operation on decoratedClass


def synchronized(decoratedFunc, trueOrFalse):
""" This describes the 'synchronized' decorator. """
__decorator__ = True
__author__ = 'Martin Curry'
__version__ = '0.5'
# perform the synchronized operation on decoratedClass


def returns(decoratedFunc, *args):
"""Docstring for 'returns' decorator."""
__decorator__ = True
# body of decorator goes here


Each decorator function receives the class|function|method being
decorated as the first parameter of the function (e.g. decoratedClass
and decoratedFunc above). The remaining parameters are the values
assigned to the __xxx__ variable in the definition of the decorated
function.

So, in the above example, when the 'returns' decorator function is
called to decorate the 'baz' method, decoratedFunc would recieve the baz
object and args[0] would be set to None (because of the statement
"__returns__ = None" in the definition of baz).

For a function to be used as a decorator function, it must be decorated
as such, by setting its __decorator__ attribute to True.

Does this handle enough of the decorator concerns?

Paul
 
L

Leif K-Brooks

Paul said:
Thinking about decorators, and looking at what we are already doing in
our Python code, it seems that __metaclass__, __author__, __version__,
etc. are all examples of decorators. So we already have a decorator
syntax. What is the compelling reason to invent a new one? And if we
do, what's to become of the old one?
<snip>

I've thought about something along the lines of your suggestion before,
but it doesn't seem very Pythonic to assign special meaning to function
variables with special names to me. It's essentially a new syntax, but
disguised as an old syntax with an entirely different meaning.
 
P

Paul Morrow

Leif said:
I've thought about something along the lines of your suggestion before,
but it doesn't seem very Pythonic to assign special meaning to function
variables with special names to me. It's essentially a new syntax, but
disguised as an old syntax with an entirely different meaning.

We just need to stop thinking of them as local function variables.
Instead we should think of __xxx__ attributes as describing the function
itself (i.e. as a decorator would), as I believe that is almost always
the author's intention when he/she uses such names inside of a
function/method definition. He wants to say something about the
function (who wrote it, it's version, etc.), and is probably sad that it
has the side-effect of creating a local variable. So it probably
shouldn't have that side-effect anymore. It should create a function
attribute instead (not to be confused with a local variable).

For classes, it's much easier to accept this new way of looking at
__xxx__ attributes because it's consistent with our intention behind
them (as names for metadata rather than normal, inheritable class
attributes).
 
L

Leif K-Brooks

Paul said:
We just need to stop thinking of them as local function variables.
Instead we should think of __xxx__ attributes as describing the function
itself (i.e. as a decorator would), as I believe that is almost always
the author's intention when he/she uses such names inside of a
function/method definition. He wants to say something about the
function (who wrote it, it's version, etc.), and is probably sad that it
has the side-effect of creating a local variable. So it probably
shouldn't have that side-effect anymore. It should create a function
attribute instead (not to be confused with a local variable).

Which is, like I said, assigning new meaning to an old syntax. That
seems confusing to me; why not just create a new syntax?
 
P

Paul Morrow

Leif said:
Which is, like I said, assigning new meaning to an old syntax. That
seems confusing to me; why not just create a new syntax?

Because it's not needed and would make the language more complex.

And I don't agree that this would be assigning new 'meaning' to an old
syntax. When a programmer creates a __xxx__ class attribute, he is not
trying to create a normal 'class' attribute --- one the is inherited by
instances of the class or that holds part of the 'state' of the class.
Instead, he is trying to make a meta statement about the class (who
wrote it, what happens during instance initialization, etc.). In that
sense, the meaning associated with defining __xxx__ attributes would
stay the same.
 
L

Leif K-Brooks

Paul said:
And I don't agree that this would be assigning new 'meaning' to an old
syntax. When a programmer creates a __xxx__ class attribute, he is not
trying to create a normal 'class' attribute --- one the is inherited by
instances of the class or that holds part of the 'state' of the class.
Instead, he is trying to make a meta statement about the class (who
wrote it, what happens during instance initialization, etc.). In that
sense, the meaning associated with defining __xxx__ attributes would
stay the same.

If we were talking about something like this:

def foo(self):
pass
foo.__author__ = "Leif K-Brooks"

then you would be correct. But when syntax normally used for assigning
to a variable magically assigns to an attribute if the variable name
starts and ends with "__", then it's an existing syntax (variable
assignment) being used for something new (attribute assignment). Why
should this:

def foo(self):
bar = 42

mean anything different from this?

def foo(self):
__bar__ = 42
 
P

Paul Morrow

Leif said:
If we were talking about something like this:

def foo(self):
pass
foo.__author__ = "Leif K-Brooks"

then you would be correct. But when syntax normally used for assigning
to a variable magically assigns to an attribute if the variable name
starts and ends with "__", then it's an existing syntax (variable
assignment) being used for something new (attribute assignment). Why
should this:

def foo(self):
bar = 42

mean anything different from this?

def foo(self):
__bar__ = 42

Because the intent of the two assignments is quite different. Yes,
their syntactic structure is similar, and what happens after they
execute is similar, but the 'kind' of information the programmer is
trying to represent is very different in the two cases.

In the first example, the programmer intends for bar to be a local
variable, used in some way by foo. In the second example, the
programmer most definitely does *not* intend for __bar__ to be used by
foo --- instead he is simply providing information *about* foo. This
better illustrates the difference.

def circumference(diameter):
__author__ = 'Paul Morrow'
__version__ = '0.1'
pi = 3.14
return pi * diameter

So when we define an __xxx__ attribute inside of a function, we are
trying to make a statement about the function --- we are not trying to
create a local variable. Therefore the Python system shouldn't create a
local variable in this case; it should create a function variable
instead (IMO).
 
L

Leif K-Brooks

Paul said:
So when we define an __xxx__ attribute inside of a function, we are
trying to make a statement about the function --- we are not trying to
create a local variable. Therefore the Python system shouldn't create a
local variable in this case; it should create a function variable
instead (IMO).

How do you think a newbie will react to magic behavior like that from
the assignment operator based entirely on the name being assigned to?
 
P

Paul Morrow

Leif said:
How do you think a newbie will react to magic behavior like that from
the assignment operator based entirely on the name being assigned to?

We must emphasize that they are assigning to a 'magic' variable, as all
__xxx__ attributes are supposed to be. One must be careful with magic :)
 
L

Leif K-Brooks

Paul said:
We must emphasize that they are assigning to a 'magic' variable, as all
__xxx__ attributes are supposed to be. One must be careful with magic :)

I'm starting to reconsider whether I like your proposal. My first
reaction was against it, since it seems like Perl-style magic behavior,
but now I'm not sure. It definitely is magic, but its purpose seems much
more clear than a lot of the other decorator proposals; that's what
Python is all about.
 
T

Tor Iver Wilhelmsen

Leif K-Brooks said:
Which is, like I said, assigning new meaning to an old syntax. That
seems confusing to me; why not just create a new syntax?

One could argue for the other way around as well: __metaclass__ et al
are class variables assigned special meaning. If new syntax for
decorators is important, why introduce the __metaclass__ "decorator"
before the new syntax is present?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top