[issue28853] locals() and free variables

New submission from Marco Buttu: The locals() documentation [1] says that "Free variables are returned by locals() when it is called in function blocks". A free variable inside a function has a global scope, and in fact it is not returned by locals()::
x = 33 def foo(): ... print(x) ... print(locals()) ... foo() 33 {}
Maybe "function blocks" here means "closure"? Does the doc mean this?
def foo(): ... x = 33 ... def moo(): ... print(x) ... print(locals()) ... return moo ... moo = foo() moo() 33 {'x': 33}
In that case, I think it is better to write "closures" instead of "function blocks". [1] https://docs.python.org/3/library/functions.html#locals ---------- assignee: docs@python components: Documentation messages: 282200 nosy: docs@python, marco.buttu priority: normal severity: normal status: open title: locals() and free variables type: enhancement versions: Python 2.7, Python 3.3, Python 3.4, Python 3.5, Python 3.6, Python 3.7 _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

Marco Buttu added the comment: In addition, also if here "function blocks" means nested function, the sentence "Free variables are returned by locals() when it is called in function blocks" I think is wrong. It is true only in case of free variables belonging to the local enclosing scope. For instance, in the following case ``x`` is free in ``moo()``, but it is not in ``locals()``::
x = 10 def foo(): ... def moo(): ... print(x) ... print(locals()) ... return moo ... moo = foo() moo() 10 {}
I attach a patch with a new description and an example. PS. Is the rst rendered by Sphinx? In that case, why we are not using the doctest Sphinx extension to test the code examples? ---------- keywords: +patch Added file: http://bugs.python.org/file45732/locals_func.patch _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

Julien Palard added the comment: Hi, thanks for reporting, Variables are defined in python docs¹ by:
If a name is bound in a block, it is a local variable of that block, unless declared as nonlocal or global. If a name is bound at the module level, it is a global variable. (The variables of the module code block are local and global.) If a variable is used in a code block but not defined there, it is a free variable.
According to this definition, global variables used in a code block are free variable, is this intentional? I think so, but can't be sure, maybe someone is seeing this as "globals are NOT free variables", in this case, this definition should probably be enhanced. If I'm right, maybe we should just change "Free variables are returned"… to "Non-global free variables are returned"…? ---------- nosy: +mdk _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

Marco Buttu added the comment: Yes, it is the same. "Free variables belonging to the enclosing local namespaces" are "non-global free variables". In order for the reader to better contextualize the sentence, I think it is worth keeping the code example in the patch. ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

R. David Murray added the comment: To answer the parenthetical question (I haven't looked at the doc issue itself), we don't doctest the examples because most of them were written before sphinx grew a doctest extension, so a lot of them don't pass for reasons that have nothing to do with code validity. Issues and patches for making the doctests pass are welcome, and we have applied a number of them. There is a lot of work to do before we could add running doctest to our doc buildbot, though. ---------- nosy: +r.david.murray _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

Xavier de Gaye added the comment: FWIW the definition of free variables can be found in the Language Reference at section 4.2.1. "Binding of names" [1]. The list of the free variables of a user defined function can be accessed through the __closure__ function attribute, a tuple. The function attributes are listed in the Language Reference at section 3.2. "The standard type hierarchy" [2]. In the example given at msg282236, the value of x would be printed by the statement: print(moo.__closure__[0].cell_contents) [1]https://docs.python.org/3/reference/executionmodel.html#naming-and-binding [2] https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarc... ---------- nosy: +xdegaye _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

Martin Panter added the comment: Marco, your patch removes the description for class blocks. Is that your intent, or just an accident? See r53954. My understanding is “function block” is there to distinguish these three modes: def foo(): # Function block print(locals()) class Bar: # Class block print(locals()) # Module level print(locals()) There are patches proposed at Issue 17546 which also address this reference to “free variables”. Perhaps you could provide feedback on them? Also see Issue 26683 and Issue 12165, about what free variables, locals, nonlocals, non-globals, etc can mean to different people. ---------- nosy: +martin.panter stage: -> patch review versions: -Python 3.3, Python 3.4 _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

Changes by Terry J. Reedy <tjreedy@udel.edu>: ---------- nosy: +terry.reedy _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

Marco Buttu added the comment: Martin, I removed the class blocks by accident. In any case, I reject the patch by myself, because to me the definition of "free variable" is not clear. The documentation [1] says: "If a variable is used in a code block but not defined there, it is a free variable." According to this description, it seems to me that ``x`` is free both in ``foo()`` and in ``moo()``:
def foo(): ... print(x) ... def moo(): ... print(x) ... return moo
But actually for the code object it is not:
foo.__code__.co_freevars () moo.__code__.co_freevars ('x',)
Thank you for your feedback, I will continue the discussion in issue 26683. [1] https://docs.python.org/3/reference/executionmodel.html#naming-and-binding ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

Marco Buttu added the comment: Sorry, in the last example, for the code object ``x`` is not free both in ``foo()`` and ``moo()``, but this does not affect the conclusion. ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

Julien Palard added the comment: Should this issue be closed so? ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________

Marco Buttu added the comment: I close it because the meaning of "free variable" is not clear. We are discussing about it in issue 26683. ---------- resolution: -> postponed status: open -> closed _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue28853> _______________________________________
participants (6)
-
Julien Palard
-
Marco Buttu
-
Martin Panter
-
R. David Murray
-
Terry J. Reedy
-
Xavier de Gaye