[Python-ideas] New syntax for 'dynamic' attribute access

Josiah Carlson jcarlson at uci.edu
Fri Feb 9 18:14:43 CET 2007


Ben North <ben at redfrontdoor.org> wrote:
> Hi,
> 
> I'd like to describe an addition I made to Python syntax which allows
> easier access to attributes where the attribute name is only known at
> run-time.  For example:
> 
>         setattr(self, method_name, getattr(self.metadata, method_name))
> 
> from Lib/distutils/dist.py could be rewritten
> 
>         self.(method_name) = self.metadata.(method_name)
> 
> As noted in the PEP-style description below, I mostly did this for
> fun, but I thought it might be worth bringing to the attention of
> python-ideas.  A quick search through prior postings and Google for
> this idea didn't come up with anything.

My only concern with your propsed change is your draft implementation...

> Draft Implementation
> 
>     A draft implementation adds a new alternative to the "trailer"
>     clause in Grammar/Grammar; a new AST type, "DynamicAttribute" in
>     Python.asdl, with accompanying changes to symtable.c, ast.c, and
>     compile.c, and three new opcodes (load/store/del) with
>     accompanying changes to opcode.h and ceval.c.  The patch consists
>     of c.180 additional lines in the core code, and c.100 additional
>     lines of tests.

Specifically, your changes to ceval.c and the compiler may have been
easier to implement, but it may negatively affect general Python
performance.  Have you run a recent pystone before and after the changes?

Since the *value* being used for the dynamic set, get, and load should
be available, it may be possible to replace the 3 new opcodes with 1 new
opcode that shifts the the value on the top of stack into the the code
object co_names, which can then be accessed directly by the standard
[LOAD|STORE|DEL]_ATTR opcodes.

The major concern with such a change is that the co_name field would no
longer be read-only, so wouldn't be sharable between threads (and would
need to grow by at least 1 when such dynamic accesses were allowed,
though growing by 2 could help in augmented assignment cases).

We could probably get away with a single new attribute on the stack
frame, adding an alternate GETITEM implementation...

#ifndef Py_DEBUG
#define GETITEM2(v, i, s) \
    ((i) != -1) ? PyTuple_GET_ITEM((PyTupleObject *)(v), (i)) : (s))
#else
#define GETITEM2(v, i, s) \
    ((i) != -1) ? PyTuple_GetItem((v), (i)) : (s))
#endif

With that change, dynamic attribute access would result in a single
opcode DYNAMIC_ACCESS, which would copy/move the value on the top of the
stack into some stack frame attribute, which is then automatically
accessed in the [LOAD|STORE|DEL]_ATTR opcodes (the GETITEM2 macro not
being used in any other opcodes).

The problem with the alternate approach above is that the overhead of
general [LOAD|STORE|DEL]_ATTR opcodes may become measurably larger
(depending on the branch prediction efficiency of a processor). 
Something to think about.


 - Josiah




More information about the Python-ideas mailing list