Limit scope of variables using round brackets
Example use cases: - Loop variables and similar, it is sometimes more comfortable to scope it to the loop body only - Not having to name variables var1, var2, var3, or makeup unnecessarily unique variable names, in some situations In other languages the curly bracket is used, in Python round brackets might fit more in the syntax. I don’t have much experience with the implementation of Python, so not sure if there’s a technical reason against such idea, feedback is very appreciated Best regards, Iyad Ahmed Email: iyadahmed@cgonfire.com Socials: Twitter <https://twitter.com/cgonfire> GitHub: https://github.com/iyadahmed
Iyad Ahmed writes:
Example use cases:
- Loop variables and similar, it is sometimes more comfortable to scope it to the loop body only - Not having to name variables var1, var2, var3, or makeup unnecessarily unique variable names, in some situations
I am not authoritative, so don't take this as a denial of the idea, but I want to give you some idea of why I suspect it is unlikely to succeed. 1. Python has a well-defined notion of *suites*, ie, indented groups of statements. If this were going to happen, I would imagine that it would be at the statement level, and most likely the syntax would be something like "block:" or "scope:" followed by an indented suite. (This is a quibble about syntax, not a reason it would be opposed in principle.) 2. Many statements in Python have suites, but only class and def create scopes. This is by design. It makes the rules for scopes simple. Since they can be used anywhere a statement can go, you can use them to create scopes (at the cost of having to invoke them later, of course). The exceptional case is that comprehensions have been changed to not leak their iteration variables, but this is basically done by implicitly defining and calling a function to create the scope if I remember correctly. 3. It's often useful to refer to the loop variable after exiting a loop. For example, if there's an explicit break in a loop controlled by a range or list, the loop variable tells you how far you got before exiting. I doubt a proposal to "close" the scope of the loop variable would be accepted. 4. It's generally considered bad style to have very long or deeply indented function bodies. Variable name collisions are more likely with global variables than with other variables in the same local scope. Perhaps for this reason, Python programmers don't frequently request more scopes. Again, the exception was the change in comprehension semantics mentioned above. which was a pain point for many. Programmers tend to think of displays more as "variable literals" than as "open-coded constructors", and therefore expect the scope to be closed. Again, I'm not authoritative, but my recommendation is to consider the above points carefully while advocating this idea. Steve
One of the few things I don't like about Python is that variable scope continues after the end of the suite the variable was created in --- probably because I think of local variable declarations as equivalent to lambdas that are called immediately, which works for most modern programming languages as well as for the theory. For example, it bugs me that you can write: if a: b = f(x) else: b = g(y) and get the same variable 'b' from it in the lines of code following that, regardless of which path was taken. I think a way to address this that would be more compatible with Python's style would be to add a new declaration syntax, perhaps borrowing from other languages and using the keyword 'let' where the variable is first assigned (and the rest of the assignment / declaration being as before). The variables declared this way would exist up to the end of the suite in which they were declared; there would be no need for any further syntax to delimit the scope. This would be fully forward-compatible, and those like me who don't like the existing scope rule could personally regard the old way of creating variables as deprecated. It would be easy for those coming to Python from various other popular languages, and I don't think it would be confusing to those learning Python as their first programming language --- the teacher / course writer could just pick either and stick with it. John On Mon, Jan 17, 2022 at 10:18 AM Stephen J. Turnbull < stephenjturnbull@gmail.com> wrote:
Iyad Ahmed writes:
Example use cases:
- Loop variables and similar, it is sometimes more comfortable to scope it to the loop body only - Not having to name variables var1, var2, var3, or makeup unnecessarily unique variable names, in some situations
I am not authoritative, so don't take this as a denial of the idea, but I want to give you some idea of why I suspect it is unlikely to succeed.
1. Python has a well-defined notion of *suites*, ie, indented groups of statements. If this were going to happen, I would imagine that it would be at the statement level, and most likely the syntax would be something like "block:" or "scope:" followed by an indented suite. (This is a quibble about syntax, not a reason it would be opposed in principle.) 2. Many statements in Python have suites, but only class and def create scopes. This is by design. It makes the rules for scopes simple. Since they can be used anywhere a statement can go, you can use them to create scopes (at the cost of having to invoke them later, of course). The exceptional case is that comprehensions have been changed to not leak their iteration variables, but this is basically done by implicitly defining and calling a function to create the scope if I remember correctly. 3. It's often useful to refer to the loop variable after exiting a loop. For example, if there's an explicit break in a loop controlled by a range or list, the loop variable tells you how far you got before exiting. I doubt a proposal to "close" the scope of the loop variable would be accepted. 4. It's generally considered bad style to have very long or deeply indented function bodies. Variable name collisions are more likely with global variables than with other variables in the same local scope. Perhaps for this reason, Python programmers don't frequently request more scopes. Again, the exception was the change in comprehension semantics mentioned above. which was a pain point for many. Programmers tend to think of displays more as "variable literals" than as "open-coded constructors", and therefore expect the scope to be closed.
Again, I'm not authoritative, but my recommendation is to consider the above points carefully while advocating this idea.
Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/BHMQ6V... Code of Conduct: http://python.org/psf/codeofconduct/
On Mon, Jan 17, 2022 at 7:36 AM John Sturdy <jcg.sturdy@gmail.com> wrote:
For example, it bugs me that you can write:
if a: b = f(x) else: b = g(y)
and get the same variable 'b' from it in the lines of code following that, regardless of which path was taken.
Really? But that is a VERY common pattern. In fact, I would find it very hard to write an enormous amount of code without it. and what if you refactored that to be: b = f(x) if a else g(x) Do you really want that to mean something different ?!?! Or are what you are getting at that if you want those two forms to be the same, then you'd need to do something like: b = None if a: b = f(x) else: b = g(y) Which means essentially that you'd like to have to declare names in order to ues them outside the very narrowest of scopes. But this is not how Python works, and it never has, it would be a really massive change, and I for one, would not like it :-( Also -- which blocks would create a new scope? All of them: for (else) while (else) with if (elif, else) try (except, else) I guess what I'm getting at is that I'm pretty sure I would find this useful rarely, and an annoyance often. - CHB -- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
On Mon, 17 Jan 2022 at 17:27, Christopher Barker <pythonchb@gmail.com> wrote:
But this is not how Python works, and it never has, it would be a really massive change, and I for one, would not like it :-(
I agree with this.
I guess what I'm getting at is that I'm pretty sure I would find this useful rarely, and an annoyance often.
And this. To be perfectly honest, I think a change like this would basically be turning Python into a different language (and not one I'd like). Even if it were done as the OP suggests using a "let" keyword to make it (technically) "optional", I'd end up seeing it in other people's code, and possibly being expected to deal with it on projects I'd be working on, and I'd hate that. So not for me, sorry. Paul
My idea is to support the style in which each variable comes into existence at a single well-defined point, whatever path is taken through the code, and so in the case of that example, it would be encouraging the use of conditional expressions. A worse case of what can be done with the scope rules for variables declared as they are now is that some code paths define the variable and some don't, so later on in the program it might or might not be defined (I have seen this done, and find it takes extra mental work to work with). I was thinking of all blocks defining scopes, like they do in C and many other languages. It would be possible to add another statement type just for this, I suppose, and have "let x = y in:" and a suite under it. On Mon, Jan 17, 2022 at 5:24 PM Christopher Barker <pythonchb@gmail.com> wrote:
On Mon, Jan 17, 2022 at 7:36 AM John Sturdy <jcg.sturdy@gmail.com> wrote:
For example, it bugs me that you can write:
if a: b = f(x) else: b = g(y)
and get the same variable 'b' from it in the lines of code following that, regardless of which path was taken.
Really? But that is a VERY common pattern. In fact, I would find it very hard to write an enormous amount of code without it. and what if you refactored that to be:
b = f(x) if a else g(x)
Do you really want that to mean something different ?!?!
Or are what you are getting at that if you want those two forms to be the same, then you'd need to do something like:
b = None if a: b = f(x) else: b = g(y)
Which means essentially that you'd like to have to declare names in order to ues them outside the very narrowest of scopes.
But this is not how Python works, and it never has, it would be a really massive change, and I for one, would not like it :-(
Also -- which blocks would create a new scope? All of them:
for (else) while (else) with if (elif, else) try (except, else)
I guess what I'm getting at is that I'm pretty sure I would find this useful rarely, and an annoyance often.
- CHB
-- Christopher Barker, PhD (Chris)
Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
On Mon, 17 Jan 2022 at 18:51, John Sturdy <jcg.sturdy@gmail.com> wrote:
My idea is to support the style in which each variable comes into existence at a single well-defined point, whatever path is taken through the code, and so in the case of that example, it would be encouraging the use of conditional expressions.
But that's a style that Python explicitly rejected right back when it was first designed, and it's fundamental to the language that you *don't* explicitly declare variables. So sorry, but it's never going to happen[1]. If you want to be really precise, technically "the style in which each variable comes into existence at a single well-defined point" is actually what Python already does. The "well-defined point" is the start of the scope (function or class definition) where the variable is used, though, and not at some new "let" keyword. To see this, look at the following:
def f(): ... print(n) ... n = 1 ... f() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in f UnboundLocalError: local variable 'n' referenced before assignment
The variable "n" exists when the print statement runs (it's unbound, but it exists - that's what the exception says), and that's because the variable comes into existence at the *start* of the scope (function). And the choice to only have a limited number of ways to define scopes is *also* a fundamental design principle of Python, so arguing that suites should each define their own scope won't get you very far either. Essentially, you're proposing to change Python to no longer be Python, in some fairly fundamental ways. Don't be surprised if you get very few supporters for your idea... Paul [1] In theory, the SC could say that such a change is fine, but I can't see that ever happening.
This is clearly one for me to abandon! Thanks for the explanations. John On Mon, Jan 17, 2022 at 7:04 PM Paul Moore <p.f.moore@gmail.com> wrote:
On Mon, 17 Jan 2022 at 18:51, John Sturdy <jcg.sturdy@gmail.com> wrote:
My idea is to support the style in which each variable comes into
existence at a single well-defined point, whatever path is taken through the code, and so in the case of that example, it would be encouraging the use of conditional expressions.
But that's a style that Python explicitly rejected right back when it was first designed, and it's fundamental to the language that you *don't* explicitly declare variables. So sorry, but it's never going to happen[1].
If you want to be really precise, technically "the style in which each variable comes into existence at a single well-defined point" is actually what Python already does. The "well-defined point" is the start of the scope (function or class definition) where the variable is used, though, and not at some new "let" keyword.
To see this, look at the following:
def f(): ... print(n) ... n = 1 ... f() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in f UnboundLocalError: local variable 'n' referenced before assignment
The variable "n" exists when the print statement runs (it's unbound, but it exists - that's what the exception says), and that's because the variable comes into existence at the *start* of the scope (function).
And the choice to only have a limited number of ways to define scopes is *also* a fundamental design principle of Python, so arguing that suites should each define their own scope won't get you very far either.
Essentially, you're proposing to change Python to no longer be Python, in some fairly fundamental ways. Don't be surprised if you get very few supporters for your idea...
Paul
[1] In theory, the SC could say that such a change is fine, but I can't see that ever happening.
Btw related question, Why it was decided that list comprehension variables are scoped? On Mon, 17 Jan 2022 at 9:06 PM John Sturdy <jcg.sturdy@gmail.com> wrote:
This is clearly one for me to abandon! Thanks for the explanations.
John
On Mon, Jan 17, 2022 at 7:04 PM Paul Moore <p.f.moore@gmail.com> wrote:
On Mon, 17 Jan 2022 at 18:51, John Sturdy <jcg.sturdy@gmail.com> wrote:
My idea is to support the style in which each variable comes into
existence at a single well-defined point, whatever path is taken through the code, and so in the case of that example, it would be encouraging the use of conditional expressions.
But that's a style that Python explicitly rejected right back when it was first designed, and it's fundamental to the language that you *don't* explicitly declare variables. So sorry, but it's never going to happen[1].
If you want to be really precise, technically "the style in which each variable comes into existence at a single well-defined point" is actually what Python already does. The "well-defined point" is the start of the scope (function or class definition) where the variable is used, though, and not at some new "let" keyword.
To see this, look at the following:
def f(): ... print(n) ... n = 1 ... f() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in f UnboundLocalError: local variable 'n' referenced before assignment
The variable "n" exists when the print statement runs (it's unbound, but it exists - that's what the exception says), and that's because the variable comes into existence at the *start* of the scope (function).
And the choice to only have a limited number of ways to define scopes is *also* a fundamental design principle of Python, so arguing that suites should each define their own scope won't get you very far either.
Essentially, you're proposing to change Python to no longer be Python, in some fairly fundamental ways. Don't be surprised if you get very few supporters for your idea...
Paul
[1] In theory, the SC could say that such a change is fine, but I can't see that ever happening.
On Sun, Jan 30, 2022 at 12:46:51AM +0200, Iyad Ahmed wrote:
Btw related question, Why it was decided that list comprehension variables are scoped?
http://python-history.blogspot.com/2010/06/from-list-comprehensions-to-gener... -- Steve
On 1/17/22 7:33 AM, John Sturdy wrote:
One of the few things I don't like about Python is that variable scope continues after the end of the suite the variable was created in --- probably because I think of local variable declarations as equivalent to lambdas that are called immediately, which works for most modern programming languages as well as for the theory. For example, it bugs me that you can write:
if a: b = f(x) else: b = g(y)
and get the same variable 'b' from it in the lines of code following that, regardless of which path was taken.
That's a feature, not a bug. A very common Python pattern is to set such common variables using if/else or try/except, and then to use those variables further along in the code *outside* the suite that set them.
I think a way to address this that would be more compatible with Python's style would be to add a new declaration syntax, perhaps borrowing from other languages and using the keyword 'let' where the variable is first assigned (and the rest of the assignment / declaration being as before). The variables declared this way would exist up to the end of the suite in which they were declared;
The syntax might be optional, but the change in semantics is not. If that change was made, then every Python programmer would have to keep track of which variables were created with `let` and then also track the lifespan of those variables which are now different from other variables in that same function or class scope. I'm sorry if programming in Python is not a choice you get to make, but that change is a huge jump in complexity for a near-zero gain. -- ~Ethan~
Hello, On Sun, 16 Jan 2022 17:31:48 +0200 Iyad Ahmed <iyadahmed430@gmail.com> wrote:
Example use cases:
- Loop variables and similar, it is sometimes more comfortable to scope it to the loop body only - Not having to name variables var1, var2, var3, or makeup unnecessarily unique variable names, in some situations
In other languages the curly bracket is used, in Python round brackets might fit more in the syntax.
I don’t have much experience with the implementation of Python, so not sure if there’s a technical reason against such idea, feedback is very appreciated
There was an idea to introduce both mutable and immutable block-scoped vars, e.g.: if 1: # Immutable aka const const x = 1 # x is undefined here if 1: # Mutable let x = 1 x = 2 # x is undefined here ("const" and "let" pretty much match the behavior of similar keywords in the modern JavaScript). If you want to see a dialect of Python with block scoped vars (and only block-scoped vars), there's Kuroko: https://github.com/kuroko-lang/kuroko . Example of its source code: https://github.com/kuroko-lang/kuroko/blob/master/test/day3.krk -- Best regards, Paul mailto:pmiscml@gmail.com
participants (8)
-
Christopher Barker
-
Ethan Furman
-
Iyad Ahmed
-
John Sturdy
-
Paul Moore
-
Paul Sokolovsky
-
Stephen J. Turnbull
-
Steven D'Aprano