Anonymous class members

Carlos Ribeiro carribeiro at gmail.com
Mon Sep 27 10:01:52 EDT 2004


I thought about this problem over the weekend, after long hours of
hacking some metaclasses to allow me to express some real case data
structures as Python classes. I think that this is something with
potential to be useful, but I would like to hear more opinions first.
If this is deemed to be useful, I *may* try to write a PEP for it.
This is not a promise or even a proposal, at this point.

Broadly generalizing, classes in Python have named members stored in
their pravate __dict__. For normal Python code, this is not an issue.
However, some types of data structures do not need named members. For
example, this is a declaration of a simple web page template that
(ab)uses a Python class declaration:

class WebPage:
    __metaclass__ = WebPageTemplate

class MyPage(WebPage):
    class header(HtmlHeader):
        title = 'My WebPage'
    class body(HtmlBody)
        H1('Anonymous class members' )
        P('This is an example of anonymous class members')

In the example above, MyPage.body contains two anonymous class
members. There are good reasons not to name them. In the case of long
templates, names are arbitrary, and most of the time are not ever
used.

I'm definining anonymous members as anything that is not a def, a
nested class, or a value that wasn't assigned or bound to name.
Everytime an expression is evaluated in the body of a class, and it's
result is *not* bound to a name, then it's value is stored the magic
_anon__ tuple. Methods or functions that return no value store None as
their return value. Named attributes don't store anything.

As a matter of fact, Python already has a related concept in the
implicit naming of the __doc__ docstring. It may or not pose a problem
for this generalization. That's my basic proposal:

class MyClass:
   """the first anonymous member is the doc string"""
   """the second anonymous member is __anon__[0]"""
   1.5 # __anon__[1] = 1.5

The docstring would be a special case -- if the first anonymous value
is a string, and iif it's the first statement, then it's stored as the
__doc__ docstring. It could (or not) be copied also at __anon__[0].
I'm not sure about it.

Some ideas and alternatives still unexplored are:

1) store the __anon__ members in the reverse order (the last value is
always at __anon__0;

2) in the case of loops, then anon members would just be stored as generated.

3) instead of the anonymous members, provide the class with an
augmented dict that can store everything that is declared inside the
class: multiple definitions of the same name, anonymous members, etc.
The mapping interface would retrieve only the named values, but an
iterator would be provided to retrieve all members, named and
anonymous, in the order they were declared. (** this is a general
solution for a wider class of applications **)

4) provide the __anon__ feature only if the metaclass creates it with
a __anon__(cls) factory method. By default, *no anonymous members
would be stored*, but if the metaclass provides a __anon__ structure,
then it's used, and passed to new as an extra keyword argument
(metaclass.__new__(cls, name, bases, dct, anon=None)).


Another alternative: augmenting the metaclass interface
------------------------------------------------------------------------

Beware: if up to this point I was in true brainstorm mode, now I'm in
a brain-hurricane-season-in-Florida mode. Be warned :-)

One alternative is to change the metaclass interface, in such a way
that it has an opportunity to catch all statements executed in the
class declaration *before* __new__ is called. A new metaclass method
(lets us call it __store__) and a generator interface to the class
definition could be provided. It would work like this:

1) Immediately upon the class declaration, Python knows what metaclass
it has to call. Either the class inherited a metaclass from an
ancestor, or __metaclass__ member is defined in the first line of the
class.

2) Python's internals check the metaclass for the __store__ function.
If it exists, it's called with the following parameters:

__metaclass__.__store__(cls, name, bases, class_generator)

3) __store__ retrieves definitions from the class_generator as tuples
of the form:

(name, value)

...where name is None for anonymous class members. At this point, the
metaclass can do whatever it pleases. It can change names, discard
values, or insert calculated values of its own.

4) __store__ returns the dict that will be passed to __new__. This
dict can be an augmented version that stores multiple definitions for
the same name, or anonymous values, or whatever is needed for the
particular class..



-- 
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: carribeiro at gmail.com
mail: carribeiro at yahoo.com



More information about the Python-list mailing list