gh-74929: Implement PEP 667 by gaogaotiantian · Pull Request #115153 · python/cpython (original) (raw)

Okay I resolved most of the comments, and I believe there's one thing left here - comprehensions.

I'm just going to jump to my proposal and see if that makes sense. If not, we can discuss it more.

import sys def f(): x = 1 [print(sys._getframe().f_locals) for a in [0]] print([sys._getframe().f_locals for a in [0]][0]) print(sys._getframe().f_locals) f()

will print

# Inside comprehension, show hidden variable a and locals in the outside frame
{'x': 1, 'a': 0}
# f_locals from inside but read outside, no hidden variable, only locals.
# This does not match the fiction because the variable should "exist" if it's a frame, but in reality it's gone
{'x': 1}
# f_locals outside, just local variables
{'x': 1}

Notice all the values above are proxies.

import sys class C: x = 1 [print(sys._getframe().f_locals) for a in [0]] print([sys._getframe().f_locals for a in [0]][0]) print(sys._getframe().f_locals)

will print (ignore __module__ and __qualname__)

# This is a proxy without class-level variable
{'a': 0}
# Empty proxy
{}
# A dict with class level variable
{'x': 1}

An alternative would be:

# A dict, but you can't write to variable a to change the local value
{'a': 0, 'x': 1}
# A dict
{'x': 1}
# Still a dict
{'x': 1}

The latter seems more consistent with the function level result, and it makes locals() backwards compatible, but it creates a horrible exemption where the f_locals is not "write through".

Maybe we could stick to a simple rule here - f_locals will always return something that's write through. locals() always return dict(proxy) or the dict itself (in class/module level, outside of the comprehension).

However, this will break the backwards compatibility for locals() in comprehension in class/module level.