Make it easier to set function globals

TL;DR: it is hard, but not impossible, to set function `__globals__` dunder to a ChainMap. Let's make it easier! Background: (1) Comprehensions skip class scope, leading to bug reports like these: https://bugs.python.org/issue3692 https://bugs.python.org/issue26951 Note Guido's comment in the first: "perhaps __globals__ could be set to a chainmap referencing the class dict and the globals?" (2) I want to experiment with namespaces, similar to the C++ feature. The details don't matter, but one way I can do that experiment is to use a class and ChainMap. So let's try an experiment: set up a namespace using ChainMap, and try to monkey-patch a function to use it instead of the regular globals. Here is my setup code: def func(): return (a, b, c) a = b = c = "global" from collections import ChainMap ns = ChainMap({'a': 'CM-0'}, {'b': 'CM-1'}, globals()) Let's see what it takes to set func.__globals__ to ns. Attempt 1: set __globals__ directly.
Attempt 2: use the FunctionType constructor.
Attempt 3: fool the constructor.
Success! And now the function behaves as desired:
f() ('CM-0', 'CM-1', 'global')
This was too hard! What can we do to make it easier? I think we should have: - allow func.__globals__ to be writable; - allow anything that inherits from the Mapping ABC. Thoughts? -- Steve

On Sun, Dec 12, 2021 at 1:23 PM Steven D'Aprano <steve@pearwood.info> wrote:
CodeType has a replace() method that returns a new code object with identical attributes but for the ones you asked to change. If making __globals__ writable causes problems, a FunctionType.replace() method would probably be a good alternative. ChrisA

On Sun, Dec 12, 2021 at 1:23 PM Steven D'Aprano <steve@pearwood.info> wrote:
CodeType has a replace() method that returns a new code object with identical attributes but for the ones you asked to change. If making __globals__ writable causes problems, a FunctionType.replace() method would probably be a good alternative. ChrisA
participants (2)
-
Chris Angelico
-
Steven D'Aprano