Two curious errors when function globals are manipulated

eryk sun eryksun at gmail.com
Tue Jul 5 11:27:15 EDT 2016


On Tue, Jul 5, 2016 at 2:46 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> I've come across two curious behaviours of a function using custom globals.
> In both cases, I have a function where __globals__ is set to a ChainMap.

ChainMap implements the MutableMapping abstract base class. But
CPython needs globals to be a dict. In the current implementation,
LOAD_GLOBAL calls _PyDict_LoadGlobal, and STORE_GLOBAL calls
PyDict_SetItem. They don't fall back on the abstract object APIs.

OTOH, when executing unoptimized code in a class, locals can be an
arbitrary mapping, e.g. as returned from a metaclass __prepare__
method. In this case, CPython LOAD_NAME and STORE_NAME fall back on
the abstract APIs PyObject_GetItem and PyObject_SetItem.

I don't see this documented in the execution and data models (maybe I
overlooked it), but it's definitely documented for exec():

    If only globals is provided, it must be a dictionary,
    which will be used for both the global and the local
    variables. If globals and locals are given, they are
    used for the global and local variables, respectively.
    If provided, locals can be any mapping object.

https://docs.python.org/3/library/functions.html?highlight=globals#exec

For example:

    >>> m = collections.ChainMap()

    >>> exec('x = 1', m)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: exec() globals must be a dict, not ChainMap

    >>> exec('x = 1', {}, m)
    >>> m['x']
    1



More information about the Python-list mailing list