* Steven D'Aprano:
One implementation-specific trick is that modifying locals does actually
work inside a class definition (at least in Python 2.5):
class Foo(object):
... x = 1
... print locals()
... locals()['x'] = 2
...
{'x': 1, '__module__': '__main__'}
Foo.x
2
But it doesn't work in functions. That is because the local variables in
CPython functions aren't stored in a dict, for efficiency reasons, so
locals() makes a copy of those variables rather than returning the actual
dict used as a namespace.
This suggests we can cause locals() to malfunction in a class too, by
using slots, since slotted attributes aren't stored in a dictionary.
That's what I would predict, but alas I'm wrong:
class Foo(object):
... __slots__ = 'x'
... x = 1
... print locals()
... locals()['x'] = 2
...
{'x': 1, '__module__': '__main__', '__slots__': 'x'}
Foo.x
2
So I don't understand why this works. Anyone know?
I don't *know*, but I have a speculation. It goes like this:
1. Perhaps first the statements in the class body are evaluated using
a dictionary for locals, with as yet no existing class object.
2. Perhaps that dictionary plus some other info is then passed to
__new__ of the class' metaclass, e.g. by default 'type' as metaclass, which
perhaps produces a class object, filling in its slots and/or __dict__ from
the supplied dictionary.
:-)
I'd have to read documentation and PEPs to say anything more for sure.
Bottom line is, modifying locals() is not supported as a language
feature. If it works, it's an accident.
By the way, when I used 'class' to create a local scope I didn't have this
behavior in mind, even if it might seem to be a strange coincidence. I just
learned the above about metaclasses, if it is a correct impression, by checking
whether the OP's declarative-like-usage code could be rescued in some way.
Unfortunately my idea, fixing up the class' __dict__ in the metaclass, didn't
work because the metaclass __new__ turned out to be called after, not before.
(Since Python can't guarantee that modifications to locals() will take, I
wonder whether it would be better to ensure that they *never* take,
rather than sometimes. It would only require locals() to return a copy of
the dict, a shallow copy would probably do.)
I agree.
Cheers,
- Alf
--
http://mail.python.org/mailman/listinfo/python-list