learning python ...

hw hw at adminart.net
Thu May 27 14:29:31 EDT 2021


When the idea is to learn something, it's not exactly helpful to abandon 
that idea when encountering the first obstacle or when someone tells you 
you don't like it as much as they do ...

On 5/25/21 7:56 AM, Avi Gross via Python-list wrote:
> I have studied many programming languages and am amused when people attack python as if every other language is somehow more optimal.
> 
> Cameron and others have provided examples but look at positives AND negatives.
> 
> Yes code like: num = int(num)
> 
> does look a tad off as it reuses the same name for something that is actually in many ways different. You could easily use a new name. But then you would have TWO variables in your name space and the old one would not be garbage collected unless you explicitly removed it. If you follow this path, would you suggest not writing: X = X + 1 either?
> 
> It is actually a fairly common practice in many languages to have code like this:
> 
> Var = read in something from a file and make some structure like a data.frame
> Var = remove some columns from the above thing pointed to by Var
> Var = make some new calculated columns ditto
> Var = remove some rows ...
> Var = set some kind of grouping on the above or sort it and so on.
> 
> As you go along you may keep transforming but have no need for earlier results, just the new and improved one. So why keep changing names? Some languages support not having any names for intermediate results by using nested function calls or pipelines.
> 
> The reality is that most languages have a series of what I loosely would call environments or name tables and as they run, new ones regularly get created and removed and even the order of them may change. The algorithm for searching for a name varies and can be in some sense linear or more complex. When looking in context for a function name, you may follow a different trail or the same one as for a variable holding a string and in some implementations the same name shadows and in others does not. Wait till you try to figure out the diamond pattern of inheritance when you create classes that depend on multiple other classes ad nauseum and you try to call a method and it tries to find the one you wanted by searching backwards in an interesting way. Many other languages decided to just not allow multiple inheritance!
> 
> How can you write a recursive function without this kind of variable shadowing? Each invocation of a function places the internal namespace in front of the parent so the meaning of a variable name used within is always backed by  all the iterations before it. But with some kinds of closures, a function may be gone and yet variables it had within it persists. Lots of odd examples more make this a complex set of CHOICES.
> 
> So what if you suggest we allow re-use of names but WARN you. OK, Python is a largely interpreted language. Normally if you ask to use a variable called X, it starts a search in the nearest place then the next one and so on till it finds it or fails. In many programs, variables are fairly local and found easily. But if you want, you can search dozens or hundreds of places and find each and every use of X visible at THIS moment and tell the user there are 82 places it can be seen and here they are. Now what? The first 50 places may be in other instances of the recursive function and you have already been warned this way 49 times and soon will be warned a few more as it continues to recurse as it travels down a tree or graph structure quite legitimately. Some of the other  places X may be in use are in some package in a part you are not even using indirectly or in middle of a for-loop as a token variable and so on. I suspect that 99.99% of the time re-using a name has no negative consequence. Making someone keep choosing names like X12346 because there is somewhere an X12345 seems a tad silly. But why go to all that expense at run-time versus in some lint program?
> 
> I recently studied a language called GO that goes to some length to protect  the user from themselves and often at great expense to getting programming done. It won't compile a program if it declares a variable and does not use it. Fair enough but I often want to write a sort of shell of a program and check as I go to make sure it works before adding more. If I will need 5 variables, I might declare them up-front then work on interactions and calculations that only include some of them and later I plan on connecting the rest. Nope, it won't let me unless I use it as in a print statement or comment it out or just remove it. Ah, but then it is not happy I did not initialize it so I set it to zero or something. Later, when I finally use it as intended, I need to remove the junk.
> 
> Some of this annoyance is so common that they had to come up with a way to shut it up. Consider this line:
> 
> Result, err = functionA(args)
> 
> It returns two arguments. Sometimes it seems silly to worry about the error but you MUST write a line of code like:
> 
> If (err != nil) {
> 	Do_something
> }
> 
> Other times you just care if it worked and don't want the result. So placing an _ for one or the other is a signal to shut the darn compiler up that you are DELIBERATELY ignoring the return value you did not want!
> 
> There are many other places the darn thing tries to protect you and insists you write code the hard way. Some are not unreasonable and some I argue are. Their method of trapping errors deliberately chose to not do the fairly common try/catch method lest it make programmers stop worrying about causing a panic, for example, or even depending on it. Their switch statement does not flow through to the next item because they worry people might forget the break statement so instead, they have a way to specify when you want execution to fall through. This last one is an example maybe of something more reasonable.
> 
> So, yes, there are languages with philosophies that may help users avoid some common mistakes. Use them if you wish. But some of these have a longer learning curve and generate lots of frustration and may make some people stop learning to program because it takes forever to get something to compile, let alone run.
> 
> In my experience, often the work-around they supply to do things is far more complex than just providing some freedom and hoping you do not abuse it. In interpreted languages, you can really do some weird things if you know more, including access to the actual names of variables and the ability to change them on the fly and so on and yes, the ability to make weird mistakes.
> 
> There can be a happy medium. Supply a function call a user can place anywhere in the code that asks if there is an "X" defined at this point in time before they use it. And, if there is, tell me about all of them as in if I remove one X, is there now another. But will that work the way you want so you can choose another name if that bothers you?
> 
> My guess is no. The same function containing your test might be called from somewhere else in your code and there is does mask something or is masked deeper. You may be using modules that change with some new release and have variables that now conflict with yours. Some identifiers are so common that the order you load packages/modules may determine which one is uppermost.
> 
> I often program in R and I do get messages when say a function called select() in package B is loaded and shadow the same name in package A or the base.  If it matters, I am free to call A::select() or B::select so the names no longer clash at that point or I use other techniques. So dynamic changes as packages are updated are possible even if my lint method once declared things to be fine. So should we force people to use fully qualified names like the above or worse?
> 
> Python is not perfect, Frankly, a good chunk of the features in python added to it as an interpreted language seem to work pretty well in various compiled languages I have studied. Many features do not require the interpreter and can now be done in other ways. Designers make choices and some are a matter of taste. Arguably Python is best for things like prototyping or even learning but arguably it is not as efficient for programs that run fairly simple algorithms constantly where running faster or using less memory can mean major savings. So, yes, often a program written in Python and shown to work, may be rewritten. But the opposite can be true as people give up trying to use a restrictive environment when the needs keep changing and a more flexible scripting language allows rapid changes.
> 
> Python is not designed or planned the way some want and if that bothers them, use something else when told by others that the language was designed to do what it is supposed to and needs no change.
> 
> On another forum someone is asking for R to not have just an NA variable when something is missing, but as many variants as needed to record why it is missing such as ILLEGIBLE or DELAYED or RAN_OUT_OF_TIME and so on. The claim is that many social science applications need this and some other programs/languages  sort of support it. Fair enough but again, the design way-back-when saw no need for this and lots of drawbacks and although we brainstormed lots of ideas on how to attach metadata to a vector to support this, it often breaks down as most existing functions toss it away so you may have to redo tons of code very carefully to preserve the data or even reapply it after a change. Something as simple as converting a vector from character strings to their integer values will drop the changes. So, again, if this is that important, use something else and do NOT suggest diddling with unused bits in one implementation of NA to store your additional metadata as there is no guarantee it will get the result you want and it is not a documented guaranteed implementation and may break lots of other existing code.
> 
> I am not discouraging anyone from asking questions and even suggesting changes. I simply suggest when others push back and tell you it was designed this way for darn good reasons and many LIKE IT the way it is, ...
> 
> 
> -----Original Message-----
> From: Python-list <python-list-bounces+avigross=verizon.net at python.org> On Behalf Of Cameron Simpson
> Sent: Monday, May 24, 2021 5:34 AM
> To: python-list at python.org
> Subject: Re: learning python ...
> 
> On 24May2021 08:21, hw <hw at adminart.net> wrote:
>> On 5/24/21 12:03 AM, Cameron Simpson wrote:
>>> On 23May2021 21:02, Stestagg <stestagg at gmail.com> wrote:
>>>> On Sun, 23 May 2021 at 20:37, hw <hw at adminart.net> wrote:
>>>>> I don't know about shadowing.
>>>>
>>>> Shadowing is effectively saying “within this bit of code, (scope) I’m
>>>> going to use an already-used name for my own value”
>>>
>>> An example might make this clearer:
>>>
>>>      x = 1 # global variable
>>>
>>>      def f(a):
>>>          x = a * 2
>>>          return x
>>>
>>> Inside the function f() the name 'x" shadows the global "x";
>>> references to "x" are to the function's local vairable. Which is very desireable.
>>
>> If it works that way, I would consider it an entirely different
>> variable.  Is there a way to access the global x from within a function
>> without transferring it through parameters of the function?
>> Than can also sometimes be useful.
> 
> Sure. You can declare a name like this:
> 
>      def f(a):
>          global x  # find x in the global namespace (the module)
>          x = a * 2
>          return x
> 
> This is pretty rare and usually discouraged. Of there are times when it is useful.
> 
> Note that in this function:
> 
>      x = 1
>      y = 2
> 
>      def f(a):
>          x = 3
>          print(x, y)
> 
> "x" is local, because the function contains an assignment to it. "y"
> comes from an outer scope (in this case, the global scope) because there's no assignment to it.
> 
>>> As Stestagg has mentioned, there are also tools called linters which
>>> warn you about issues like this. Tools like pyflakes, pylint,
>>> pycodestyle all inspect your code for a wide variety of potential
>>> errors and discouraged habits.  Not to mention tools like mypy which
>>> do type validation.
>>
>> So you're saying one can't really go without those unless you want to
>> take the risk?
> 
> Self restraint and developing good habits does 99% of the work. Linters are great for catching various accidents.
> 
> [...]
>> I'm not saying it shouldn't be allowed to defeat or to re-define stuff,
>> only that it shouldn't go through quietly.
> 
> Well, most of us use linters to exhibit that noise, rather than requiring the code to be littered with special directives.
> 
> I usually code without much linter fuss until I've got the latest batch of work (eg feature or fix) ready, commit the changes, then lint vigorously and commit that polish before merging with the main line of code.
> 
> Finally, consider this code:
> 
>      num = input("Enter a number: ")
>      num = int(num)
> 
> input() returns a string, which would need converting to a number before some numeric stuff. Plenty of people write the above. To my mind, this is also a kind of shadowing, and I like this instead:
> 
>      num_s = input("Enter a number: ")
>      num = int(num_s)
> 
> where the "_s" indicates quietly that this variable holds a string.
> 
> Is that shadowing to your mind? Or not? If yes, should the language emit noise there, too? Remembering that Python _values_ are strongly typed, though the variables are not (a variable might reference any kind of object, as above).
> 
> I wouldn't say that your opinion would be wrong regardless of what side of this question you come down on, but Python's chosen a side: noise for nonsensical things, but not noise for dubious things. But plenty of linters to complain about dubious things.
> 
> Cheers,
> Cameron Simpson <cs at cskk.id.au>
> --
> https://mail.python.org/mailman/listinfo/python-list
> 



More information about the Python-list mailing list