
Dear Mous[e], On 29/11/2022 14.49, Anony Mous wrote:
As it stands now, to create a local scope, you must define a function. ...
Good coding practice is generally accepted to be that variables are local if at all possible. However, in direct, inline Python code, we're inherently creating variables with a global scope.
(inline) inherently?
We don't actually need a function for this kind of code; but a local scope would often be valuable (as we see with lambda.) Moving things off into a function can create a circumstance where we have to go looking for the function. When something is a "one-shot" as in global preparatory code, that's doing more work, and creating more indirection, than needs actually be done. But global operations have their own pitfalls, one of which is variable collisions. So Python sort of drives us to make "one-use" functions where lambdas are insufficient to the case in order to control locality.
You can end up writing things like...
def PrepOne(): for MyCount in range(0,10): pass
PrepOne()
...which achieves the locality desired for variable MyCount, but is clunky. It also clutters the global namespace with prepOne, which has no good reason to exist.
The larger criticism of the above is the chosen-name (not referring to PEP-008). The opportunity a function gives, is to name a unit of code. This is the way people think - often called "chunking". Whereas 'Apprentices' think (perhaps) one line of code at a time, more experienced pythonista think in larger 'lumps', eg 'need to sum the first ten (non-negative) digits'. The actual code to deliver such a sub-objective is the same, either in-line or as a function. However, deliberating over the choice of name for the function makes the code easy to read - indeed, coming to it later, (and assuming some trust in the author), at first it wouldn't be necessary read the function's code, if the name enabled comprehension. Test-oriented folk will also point-out that the function/sub-objective can be tested, even proven, without regard to other aspects of the code, or the progress of development 'elsewhere'. ...
This is the scoping equivalent of a pair of curly braces in c and c++. I would like to see it be nestable, as scopes are in c/c++:
Aside: statements seeking justification from other languages invite an obvious retort, along the lines of 'use [what you think is] the best tool for the job'.
local: # <== or whatever syntax makes sense for MyCount in range(0,10): local: for YourCount in range(0,MyCount+1) pass
Please allow appropriate of the word "clunky". This example features two uses of "local:" which contribute nothing except to isolate MyCount and YourCount (sic). In addition to this 'noise' in the code, there is an extra level of indentation for each "local:". (please refer back to 'the early days' and the Python blocks-by-indentation discussions, and the debates over tabs cf how-many-spaces, leading to the idea of code marching off-the-page to the right). Functions (also) enable a tidy form of nesting.
There, MyCount is available in both scopes (the first local: is an enclosing scope) and YourCount is available only in the second local: scope.
Or, local: could be very strict, and require further syntax to incorporate a previous scope, something like this:
Can Python be described as a "strict" language? Compared to which other languages? ... Perhaps the very flexibility of Python is its power? The attitude of 'we're all adults here' suggests that some ideas are not "good", eg globals; but if one has sufficient reason (or foolishness), then proceed - but at your own risk! (see also Python object-attribute addressing through dotted-notation cf formal getters and setters). One of the challenges I faced coming to Python - and still notice from time-to-time, is accepting the informality, the EAFP (cf LBYL) attitude. However, one lives and learns... OTOH given that programming has been described as "choosing good names", I can't remember the last time a naming-collision/scope-issue proved that I'm not the smartest person in the room... -- Regards, =dn