On Tue, Jul 5, 2016 at 2:46 PM, Steven D'Aprano <st...@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
-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to