What do we think of adding a built-in nonlocals() function that would be similar to globals() and locals()? Like those functions, it would return a dictionary of variable names and their values. Since we now have the nonlocal statement, it would be consistent to keep the three scopes local/nonlocal/global with parallel capabilities. And it might sometimes be useful for code inside a nested function to see what variables are available at the enclosing level. Steve Bonner
Steve Bonner wrote:
What do we think of adding a built-in nonlocals() function that would be similar to globals() and locals()? Like those functions, it would return a dictionary of variable names and their values. Since we now have the nonlocal statement, it would be consistent to keep the three scopes local/nonlocal/global with parallel capabilities. And it might sometimes be useful for code inside a nested function to see what variables are available at the enclosing level.
That isn't as easy as it may sound. locals() and globals() are each single namespaces, while the nonlocals may actually span multiple namespaces. Python actually deals with this at compilation time and when the function object is created - the interpreter knows the names of all the nonlocal cells that need to be connected, and creates the appropriate links to the cells in the outer scopes. That situation doesn't translate well to dict-style access - while the whole local namespace is readily accessible to the interpreter, as is a pointer to the module namespace (for globals()), no such convenient data source exists for the full set of possible nonlocal references from an arbitrary function. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia ---------------------------------------------------------------
Steve Bonner <pythonsteve <at> gmail.com> writes:
What do we think of adding a built-in nonlocals() function that would be similar to globals() and locals()? Like those functions, it would return a dictionary of variable names and their values. Since we now have the nonlocal statement, it would be consistent to keep the three scopes local/nonlocal/global with parallel capabilities.
These scopes don't have parallel capabilities:
def f(): ... x = 5 ... locals()['x'] = 6 ... return x ... f() 5
And it might sometimes be useful for code inside a nested function to see what variables are available at the enclosing level.
"It might sometimes be useful" translates in my head to "I've never seen an actual use case for this". -1 on an useless complication of the interpreter.
Antoine Pitrou wrote:
Steve Bonner <pythonsteve <at> gmail.com> writes:
What do we think of adding a built-in nonlocals() function that would be similar to globals() and locals()?
These scopes don't have parallel capabilities:
Maybe it would be better to deprecate globals() and locals() and replace them with another function called something like scope(). It would return a mapping object that looks up names in the current scope. It could also improve on locals() by being writable. -- Greg
On 06/04/2010 00:37, Greg Ewing wrote:
Antoine Pitrou wrote:
Steve Bonner <pythonsteve <at> gmail.com> writes:
What do we think of adding a built-in nonlocals() function that would be similar to globals() and locals()?
These scopes don't have parallel capabilities:
Maybe it would be better to deprecate globals() and locals() and replace them with another function called something like scope(). It would return a mapping object that looks up names in the current scope. It could also improve on locals() by being writable.
Well, not a bad idea but it belongs on python-ideas and would be covered by the language moratorium. :-) Michael -- http://www.ironpythoninaction.com/ http://www.voidspace.org.uk/blog READ CAREFULLY. By accepting and reading this email you agree, on behalf of your employer, to release me from all obligations and waivers arising from any and all NON-NEGOTIATED agreements, licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap, confidentiality, non-disclosure, non-compete and acceptable use policies (”BOGUS AGREEMENTS”) that I have entered into with your employer, its partners, licensors, agents and assigns, in perpetuity, without prejudice to my ongoing rights and privileges. You further represent that you have the authority to release me from any BOGUS AGREEMENTS on behalf of your employer.
Greg Ewing <greg.ewing <at> canterbury.ac.nz> writes:
Maybe it would be better to deprecate globals() and locals() and replace them with another function called something like scope().
It is useful to distinguish between globals (i.e., module-level variables) and locals, so replacing them with scope() would not be better IMO.
It would return a mapping object that looks up names in the current scope. It could also improve on locals() by being writable.
If you can prove that making locals() (or its replacement) writable doesn't complicate the interpreter core too much, then why not. Otherwise -1 :-) Regards Antoine.
On Mon, Apr 5, 2010 at 7:35 PM, Antoine Pitrou <solipsis@pitrou.net> wrote:
If you can prove that making locals() (or its replacement) writable doesn't complicate the interpreter core too much, then why not. Otherwise -1 :-)
I think writable locals would significantly complicate the job of people trying to optimize Python. The current situation is that so long as a code object is compiled with certain flags and avoids using exec, then it is impossible to indirectly modify locals in a call frame without resorting to compiled code that mucks with the frame directly. It was very easy for us to check for these conditions, and if they were met, emit faster code. Collin implemented/optimized local variable access for unladen, so he would know more than I. If I remember correctly, the exec statement is going away in py3k, and calling exec() with one argument can modify the local scope. Therefore we'll probably have to do something more sophisticated anyway. :( This would impact PyPy, Jython, and the other implementations, so I would think twice about it. Reid
Reid Kleckner wrote:
If I remember correctly, the exec statement is going away in py3k, and calling exec() with one argument can modify the local scope.
I've been kind of wondering what the deal is with exec in py3. I always thought the reason for making exec a statement was so that locals optimisation could be turned off in its presence, so I'm not sure how py3 is getting away with making it a function. Anyhow, it seems to me that as long as locals() or whatever might replace it is able to find the existing value of a local, it should also be able to change that value, wherever it happens to be stored. I suppose that might fail if an optimiser decides to keep multiple copies of a local for some reason, though. But even if it has to be read-only, I still think a view object would be a more py3ish way of handling locals() and the like. You might only want access to a few locals, in which case building a dict containing all of them would be wasteful. -- Greg -- Greg
On Tue, Apr 6, 2010 at 11:13 AM, Greg Ewing <greg.ewing@canterbury.ac.nz>wrote:
Reid Kleckner wrote:
If I remember correctly, the exec statement is going away in py3k, and
calling exec() with one argument can modify the local scope.
I've been kind of wondering what the deal is with exec in py3. I always thought the reason for making exec a statement was so that locals optimisation could be turned off in its presence, so I'm not sure how py3 is getting away with making it a function.
It looks like py3 does not allow exec to modify the locals: $ python3 Python 3.1.1 (r311:74543, Aug 24 2009, 18:44:04) [GCC 4.0.1 (Apple Inc. build 5493)] on darwin Type "help", "copyright", "credits" or "license" for more information.
def x(a): ... exec(a) ... return a ... x("a = 5") 'a = 5' # the above statement would have returned 5 if the locals had been modified
Anyhow, it seems to me that as long as locals() or whatever might replace it is able to find the existing value of a local, it should also be able to change that value, wherever it happens to be stored.
I suppose that might fail if an optimiser decides to keep multiple copies of a local for some reason, though.
But even if it has to be read-only, I still think a view object would be a more py3ish way of handling locals() and the like. You might only want access to a few locals, in which case building a dict containing all of them would be wasteful.
-- Greg
-- Greg
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/thobes%40gmail.com
2010/4/6 Antoine Pitrou <solipsis@pitrou.net>
Greg Ewing <greg.ewing <at> canterbury.ac.nz> writes:
Maybe it would be better to deprecate globals() and locals() and replace them with another function called something like scope().
It is useful to distinguish between globals (i.e., module-level variables) and locals, so replacing them with scope() would not be better IMO.
It would return a mapping object that looks up names in the current scope. It could also improve on locals() by being writable.
If you can prove that making locals() (or its replacement) writable doesn't complicate the interpreter core too much, then why not. Otherwise -1 :-)
Regards
Antoine.
It will certainly. There's MUCH that can be optimized to let CPython squeeze more performance from static analysis (even a gross one) on locals. Example: def f(): a = 1 b = 2 return a + b can be reduced to something similar to: def f(): a = 1 b = 2 return 3 and, more aggressively, like: def f(): return 3 They are just "dummy" examples, but can make it clear how far optimizations can go with static analysis on locals. Python is a language that make it possible to use such analysis at compile time, and I think it is a very good thing. Obviously the last example brings questions regards the language semantic: is it right to suppress "unused" or "not useful" local variables? A "conservative" answer will be clearly NO. But I hope that a future language specification will fix some aspects, putting clear what you can expect from the language itself, and what is closet to the implementation. Cesare
Cesare Di Mauro wrote:
It will certainly. There's MUCH that can be optimized to let CPython squeeze more performance from static analysis (even a gross one) on locals.
But can the existing locals() function be implemented in the face of such optimisations? If it can, then a "locals view" object shouldn't be too much harder. If it can't, then you have already given up full CPython compatibility. -- Greg
2010/4/6 Greg Ewing <greg.ewing@canterbury.ac.nz>
Cesare Di Mauro wrote:
It will certainly. There's MUCH that can be optimized to let CPython
squeeze more performance from static analysis (even a gross one) on locals.
But can the existing locals() function be implemented in the face of such optimisations?
If it can, then a "locals view" object shouldn't be too much harder.
If it can't, then you have already given up full CPython compatibility.
-- Greg
A read-only locals view can be a good comprise, because at least the first example I showed can be approached well. For the second example, there's no full compatibility with the current CPython implementation. But implementations can change over the time: we can clearly define that on future CPython versions no assumptions must be made about locals "usage", and in general about instructions generation. The most important thing is that the function f() does what is called to do: return the numeric constant 3. This gives us the opportunity to schedule more efficient optimizations, without losing generality about the language (only some weird tricks will not be supported). Cesare
On Tue, 6 Apr 2010 04:25:08 pm Cesare Di Mauro wrote:
It will certainly. There's MUCH that can be optimized to let CPython squeeze more performance from static analysis (even a gross one) on locals. [...] They are just "dummy" examples, but can make it clear how far optimizations can go with static analysis on locals. Python is a language that make it possible to use such analysis at compile time, and I think it is a very good thing.
I'm not opposed to the idea of optimisations in general (far from it!) but in case anyone is thinking about doing any work in this area, please be careful about floating point optimisations. E.g. given a float x, you can't assume that x*0 == 0. Nor can you assume that 0-x is the same as -x. (The second is *almost* always correct, except for one float value.) See, for example, the various writings by Professor Kahan: http://www.drdobbs.com/184410314 http://www.cs.berkeley.edu/~wkahan/ Most of the issues discussed apply to languages that deal with floats at a lower level than Python does, but still, simple minded optimizations will break corner cases no matter what language you use. -- Steven D'Aprano
2010/4/7 Steven D'Aprano <steve@pearwood.info>
On Tue, 6 Apr 2010 04:25:08 pm Cesare Di Mauro wrote:
It will certainly. There's MUCH that can be optimized to let CPython squeeze more performance from static analysis (even a gross one) on locals. [...] They are just "dummy" examples, but can make it clear how far optimizations can go with static analysis on locals. Python is a language that make it possible to use such analysis at compile time, and I think it is a very good thing.
I'm not opposed to the idea of optimisations in general (far from it!) but in case anyone is thinking about doing any work in this area, please be careful about floating point optimisations. E.g. given a float x, you can't assume that x*0 == 0. Nor can you assume that 0-x is the same as -x. (The second is *almost* always correct, except for one float value.)
See, for example, the various writings by Professor Kahan:
http://www.drdobbs.com/184410314 http://www.cs.berkeley.edu/~wkahan/
Most of the issues discussed apply to languages that deal with floats at a lower level than Python does, but still, simple minded optimizations will break corner cases no matter what language you use.
-- Steven D'Aprano
Thanks for the useful links. I never applied such kind of optimizations, and I think I'll never to do it anyway. :) Cesare
participants (9)
-
Antoine Pitrou
-
Cesare Di Mauro
-
Greg Ewing
-
Michael Foord
-
Nick Coghlan
-
Reid Kleckner
-
Steve Bonner
-
Steven D'Aprano
-
Tobias Ivarsson