Are decorators really that different from metaclasses...

Bengt Richter bokr at oz.net
Thu Aug 26 15:46:19 EDT 2004


On Thu, 26 Aug 2004 11:15:46 -0400, Paul Morrow <pm_mon at yahoo.com> wrote:

>Anthony Baxter wrote:
>
>> On Thu, 26 Aug 2004 09:50:43 -0400, Paul Morrow <pm_mon at yahoo.com> wrote:
>> 
>>>Ok.  Then let's jettison the baggage with the word metadata and just
>>>call them 'magic attributes'.  It doesn't matter.  The essential point
>>>about them is that they almost /never have 'local variable' semantics/.
>>>They are attributes of the object being defined.  That's the point I'm
>>>trying to drive home here.  When we define __xxx__ attributes, we are
>>>not intending to create local variables.  No.  We are making declarations.
>> 
>> 
>> Explain to me how __getitem__ is a declaration while getMonkey is not,
>> assuming both are methods.
>> 
>> The only magic attribute that fits your case of "magic attribute" is
>> __metaclass__.
>> The overwhelming number of double-under names are not magic
>> attributes, or metadata, or whatever you want to call them.
>
>__getitem__ is most certainly magical!  Defining it 'declares' 
>(implicitly, but we'll ignore that governing zen rule for the moment) 
>that instances of the containing class have dictionary semantics (that 
>they can be used, in some degree, like dictionaries).  That's magic.
No, it's convention. The convention is that you should write __getitem__
methods for YourClass so that if ycinst = YourClass() then ycinst[key_or_index]
will not break expectation of dict-like or sequence-like access too badly.
But you are free to break the convention.

The __getitem__ name serves as a hook into implementation of ycinst[key_or_index]
which has been designed to use __getitem__ in a predictable way. Similarly with
other double-underscore methods. The names don't declare anything. Their use in
a predictable way by generated code just gives you the opportunity to hook in
your own magic for source that translates to use of such methods.

Your proposal exposes the peculiar sematics of the doc string, which really should
become a discarded string expression where it now appears. IMO it might have been as
good or better to capture text from the first block of comments inside a function
and bind __doc__ to that. Then statement semantics would have been more consistent.

But you are going in the other direction, expanding on special statement semantics
in special contexts, and making double underscore names into special sugar for
something more than names, not just special names with special conventional bindings.
I.e., your __xxx__ becomes a spelling for foo.__xxx__ etc. and an implied moving of
the code to post-definition execution context. I'd rather do that with a prefixed
using: block than with special interpretation of names.

I would rather see see some way to access the current object and its environment
without using its post-definition name binding, and controlling _when_ statements
execute. The decorator syntax provide a when of post-def-execution-pre-name-binding
and it provides current-object binding via the binding to the parameter in the
decorator call. The _when_ for statements in a function body is during-call-execution.
I'd like some of the internal whens to be exposed and hookable. E.g., expanding on
try/finally to provide keyword:suite syntax for what is e.g. currently done with
default-argument hack -- i.e., def-execution-time initialization of values
for every-call-time initialization of local bindings to those values. A version of
that might provide persistent local bindings -- like a private writable closure.

<musing>
A __self__ magic binding could provide access to the current object, and __self__.__enclosing__
could be magic for accessing the textually enclosing entity, which might have another enclosing
entity, so __self__.__enclosing__.__enclosing__ would then be legal. Dynamic spaces similarly,
perhaps locals() and outwards to locals(1) etc.
</musing>

>That's meta.  That's profoundly deeper than anything defining getMonkey 
>does.

ISTM you are looking at __getitem__ from the wrong end of the magic.
The name is a standard method name that various specific source code texts
will generate code to access, e.g. x[3] or x.__class__.__dict__['__getitem__'](x, 3).
The magic is in what people have done with the names, not the names themselves.
The source spelling for generating code using the __metaclass__ name is admittedly
a bit more mysterious than x[y] generating code using __getitem__ ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list