[Python-ideas] New syntax for 'dynamic' attribute access
jcarlson at uci.edu
Fri Feb 9 18:14:43 CET 2007
Ben North <ben at redfrontdoor.org> wrote:
> 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
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...
#define GETITEM2(v, i, s) \
((i) != -1) ? PyTuple_GET_ITEM((PyTupleObject *)(v), (i)) : (s))
#define GETITEM2(v, i, s) \
((i) != -1) ? PyTuple_GetItem((v), (i)) : (s))
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.
More information about the Python-ideas