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