Mailing List Archive

OT: Addition of a .= operator
On 24/05/2023 10.21, Rob Cliffe via Python-list wrote:
>
>> This sort of code might be better as a single expression. For example:
>>
>> user = (
>>      request.GET["user"]
>>      .decode("utf-8")
>>      .strip()
>>      .lower()
>> )
>> user = orm.user.get(name=user)
>>
>>
> LOL.  And I thought I was the one with a (self-confessed) tendency to
> write too slick, dense, smart-alec code. ????
> Indeed, I was itching to shorten it (starting with the low-hanging
> fruit: user = user.strip().lower() ).
> Seriously though: this kind of condensation can come unstuck when any of
> the steps need to be made more complicated.
...

> Peter's actual code feels more Pythonic to me.  (It's even 2 lines
> shorter! ????)

On 24/05/2023 09.03, Peter J. Holzer wrote:
> I sometimes have a chain of transformations (e.g. first decode it, then
> strip extra spaces, then normalize spelling, then look it up in a
> database and replace it with the record, ...). Technically, of course
> all these intermediate objects are different, and I could make that
> explicit by using different variable names:
>
> user_param = request.GET["user"]
> user_decoded = str(user_param, encoding="utf-8")
> user_stripped = user_decoded.strip()
> user_normalized = user_stripped.lower()
> user_object = orm.user.get(name=user_normalized)
>
> But I find it easier to read if I just reuse the same variable name:
>
> user = request.GET["user"]
> user = str(user, encoding="utf-8")
> user = user.strip()
> user = user.lower()
> user = orm.user.get(name=user)
>
> Each instance only has a livetime of a single line (or maybe two or
> three lines if I have to combine variables), so there's little risk of
> confusion, and reusing the variable name makes it very clear that all
> those intermediate results are gone and won't be used again.


Once again/recently/another trainee came with a question about input()
because he expected an number (cf input() providing a string). In this
case, and to drive-home the point, preferred training illustration is:

quantity_input = input( "How many would you like? " )
quantity = float( quantity_input )

Many others, and I dare so all those who suffer from the aforementioned
"itch", want to condense this into a single line.

However, (continuing @Peter's theme) such confuses things when something
goes wrong - was the error in the input() or in the float()?
- particularly for 'beginners'
- and yes, we can expand the above discussion to talk about
error-handling, and repetition until satisfactory data is input by the
user or (?frustration leads to) EOD...

Accordingly, I'd start by favoring @Peter's "explicit" approach. However
(as mentioned), we end-up with a bunch of names (storage-space) which
are essentially unused - and many lint-er types will deplore such
single-use [like it's s-u plastic].

Thus, advice becomes somewhat the opposite(!) of function parameter
handling - there, I'm happy with one or two positional-parameters, but
by three-or-more, this over-taxed brain starts begging/itching for
named-parameters instead.

Now, the "easier" approach appeals. Indeed, if something goes wrong (per
input()/float(), above), at least one has the assistance of a
line-number (where error was noted). Further, using the PyCharm
Debugger/pdb makes locating the design-error/coder's mistaken
assumption, a snap.

A debatable-point is how much we should consider more junior-level
programmers. IMHO more common functions such as strip() and lower() can
be combined without much loss of readability or comprehension (apart
from 'function-chaining' adding complication). Whereas, the other three
lines are more likely to challenge - and/or become a source of concern
if mods are requested...

However, some disagreement - which comes back to why the "_input" suffix
(above) acts as an aide-memoire: When "user" is first used (hah!), it is
the result of an http request. It is then transmogrified, until at the
end where it is a query-result/object. Yes, however contrived and
deliberately drawn-out the example, there is still a difference between
the value which the code first produces (request/input) and that which
eventually settles-out (orm/float).

Accordingly (perhaps), "user_request" or "user_requested" and "user" or
"user_record" (according to the way 'that' ORM operates). Perhaps more
psychology rather than coding?

--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: OT: Addition of a .= operator [ In reply to ]
On Wed, 24 May 2023 at 10:12, dn via Python-list <python-list@python.org> wrote:
> However, (continuing @Peter's theme) such confuses things when something
> goes wrong - was the error in the input() or in the float()?
> - particularly for 'beginners'
> - and yes, we can expand the above discussion to talk about
> error-handling, and repetition until satisfactory data is input by the
> user or (?frustration leads to) EOD...

A fair consideration! Fortunately, Python has you covered.

$ cat asin.py
import math

print(
math.asin(
float(
input("Enter a small number: ")
)
)
)
$ python3 asin.py
Enter a small number: 1
1.5707963267948966
$ python3 asin.py
Enter a small number: 4
Traceback (most recent call last):
File "/home/rosuav/tmp/asin.py", line 4, in <module>
math.asin(
ValueError: math domain error
$ python3 asin.py
Enter a small number: spam
Traceback (most recent call last):
File "/home/rosuav/tmp/asin.py", line 5, in <module>
float(
ValueError: could not convert string to float: 'spam'

Note that the line numbers correctly show the true cause of the
problem, despite both of them being ValueErrors. So if you have to
debug this sort of thing, make sure the key parts are on separate
lines (even if they're all one expression, as in this example), and
then the tracebacks should tell you what you need to know.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: OT: Addition of a .= operator [ In reply to ]
On 24/05/2023 12.27, Chris Angelico wrote:
> On Wed, 24 May 2023 at 10:12, dn via Python-list <python-list@python.org> wrote:
>> However, (continuing @Peter's theme) such confuses things when something
>> goes wrong - was the error in the input() or in the float()?
>> - particularly for 'beginners'
>> - and yes, we can expand the above discussion to talk about
>> error-handling, and repetition until satisfactory data is input by the
>> user or (?frustration leads to) EOD...
>
> A fair consideration! Fortunately, Python has you covered.
>
> $ cat asin.py
> import math
>
> print(
> math.asin(
> float(
> input("Enter a small number: ")
> )
> )
> )
> $ python3 asin.py
> Enter a small number: 1
> 1.5707963267948966
> $ python3 asin.py
> Enter a small number: 4
> Traceback (most recent call last):
> File "/home/rosuav/tmp/asin.py", line 4, in <module>
> math.asin(
> ValueError: math domain error
> $ python3 asin.py
> Enter a small number: spam
> Traceback (most recent call last):
> File "/home/rosuav/tmp/asin.py", line 5, in <module>
> float(
> ValueError: could not convert string to float: 'spam'
>
> Note that the line numbers correctly show the true cause of the
> problem, despite both of them being ValueErrors. So if you have to
> debug this sort of thing, make sure the key parts are on separate
> lines (even if they're all one expression, as in this example), and
> then the tracebacks should tell you what you need to know.


Yes, an excellent example to show newcomers to make use of 'the
information *provided*' - take a deep breath and read through it all,
picking-out the important information...


However, returning to "condense this into a single line", the
frequently-seen coding is (in my experience, at least):

quantity = float( input( "How many would you like? " ) )

which would not produce the helpful distinction between
line-numbers/function-calls which the above (better-formatted) code does!


Summarising (albeit IMHO):

- if relatively trivial/likely to be well-known: collect the calls into
a chain, eg

user = user.strip().lower()

- otherwise use separate lines in order to benefit from the stack-trace

- (still saying) use separate assignments, rather than chaining more
complex/lesser-known combinations

- ensure that the 'final' identifier is meaningful (and perhaps the
first, and/or even an 'intermediate' if pertinent or kept for re-use later)

- perhaps re-use a single identifier-name as a temp-variable, if can
reasonably 'get away with it'
(and not confuse simple minds, like yours-truly)


--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
RE: OT: Addition of a .= operator [ In reply to ]
It may be a matter of taste and policies, Dave.

I am talking about whether to write your code so it looks good to you, and
dealing with issues like error messages only when needed, or whether to
first do all kinds of things to catch errors or make it easier if they pop
up.

Python can be written fairly compactly and elegantly when trying out an
algorithm. But if you pepper it with print statements all over the place
showing the current values of variables and return codes (perhaps commented
out or hiding in an IF statement set to False) then you have a version
harder to read even if it can potentially be very useful. If your code is
constantly specifying what types variables must be or testing constraints,
it may well compile but for some users all that gets in the way of seeing
the big picture.

In this case, we are discussing issues like how to spread code onto multiple
lines and opinions differ. In languages that do not use indentation as
having special meaning, I often like to stretch out and use lots of lines
for something like a function call with umpteen arguments and especially one
containing nested similar dense function calls. A good text editor can be
helpful in lining up the code so things at the same indentation level have
meaning as do things at other levels.

I will say that the try/catch type idioms that surround every piece of code,
often nested, can make code unreadable.

Similarly, some languages make it easy to do chaining in ways that use
multiple lines.

Since python is (justifiably) picky about indentation, I use such features
less and more cautiously and sometimes need to carefully do things like add
parentheses around a region to avoid inadvertent misunderstandings.

When I do my work for myself and am not expecting serious errors I tend to
write the main program first and only then enhance it as needed. If working
with a group and established standards, of course, we follow whatever
methods are needed, and especially if a large part of the effort is to test
thoroughly against requirements.



-----Original Message-----
From: Python-list <python-list-bounces+avi.e.gross=gmail.com@python.org> On
Behalf Of dn via Python-list
Sent: Wednesday, May 24, 2023 1:19 AM
To: python-list@python.org
Subject: Re: OT: Addition of a .= operator

On 24/05/2023 12.27, Chris Angelico wrote:
> On Wed, 24 May 2023 at 10:12, dn via Python-list <python-list@python.org>
wrote:
>> However, (continuing @Peter's theme) such confuses things when something
>> goes wrong - was the error in the input() or in the float()?
>> - particularly for 'beginners'
>> - and yes, we can expand the above discussion to talk about
>> error-handling, and repetition until satisfactory data is input by the
>> user or (?frustration leads to) EOD...
>
> A fair consideration! Fortunately, Python has you covered.
>
> $ cat asin.py
> import math
>
> print(
> math.asin(
> float(
> input("Enter a small number: ")
> )
> )
> )
> $ python3 asin.py
> Enter a small number: 1
> 1.5707963267948966
> $ python3 asin.py
> Enter a small number: 4
> Traceback (most recent call last):
> File "/home/rosuav/tmp/asin.py", line 4, in <module>
> math.asin(
> ValueError: math domain error
> $ python3 asin.py
> Enter a small number: spam
> Traceback (most recent call last):
> File "/home/rosuav/tmp/asin.py", line 5, in <module>
> float(
> ValueError: could not convert string to float: 'spam'
>
> Note that the line numbers correctly show the true cause of the
> problem, despite both of them being ValueErrors. So if you have to
> debug this sort of thing, make sure the key parts are on separate
> lines (even if they're all one expression, as in this example), and
> then the tracebacks should tell you what you need to know.


Yes, an excellent example to show newcomers to make use of 'the
information *provided*' - take a deep breath and read through it all,
picking-out the important information...


However, returning to "condense this into a single line", the
frequently-seen coding is (in my experience, at least):

quantity = float( input( "How many would you like? " ) )

which would not produce the helpful distinction between
line-numbers/function-calls which the above (better-formatted) code does!


Summarising (albeit IMHO):

- if relatively trivial/likely to be well-known: collect the calls into
a chain, eg

user = user.strip().lower()

- otherwise use separate lines in order to benefit from the stack-trace

- (still saying) use separate assignments, rather than chaining more
complex/lesser-known combinations

- ensure that the 'final' identifier is meaningful (and perhaps the
first, and/or even an 'intermediate' if pertinent or kept for re-use later)

- perhaps re-use a single identifier-name as a temp-variable, if can
reasonably 'get away with it'
(and not confuse simple minds, like yours-truly)


--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list

--
https://mail.python.org/mailman/listinfo/python-list
Re: OT: Addition of a .= operator [ In reply to ]
On 2023-05-24 12:10:09 +1200, dn via Python-list wrote:
> Perhaps more psychology rather than coding?

Both. As they say, coding means writing for other people first, for
the computer second. So that means anticipating what will be least
confusing for that other person[1] who's going to read that code.

hp

[1] Which is often yourself, a few months older. Or it could be an
experienced colleague who's very familiar with the codebase. Or a new
colleague trying to understand what this is all about (possibly while
learning Python).

--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"
Re: OT: Addition of a .= operator [ In reply to ]
On Wed, May 24, 2023 at 05:18:52PM +1200, dn via Python-list wrote:
>>Note that the line numbers correctly show the true cause of the
>>problem, despite both of them being ValueErrors. So if you have to
>>debug this sort of thing, make sure the key parts are on separate
>>lines (even if they're all one expression, as in this example), and
>>then the tracebacks should tell you what you need to know.
>
>
>Yes, an excellent example to show newcomers to make use of 'the
>information *provided*' - take a deep breath and read through it all,
>picking-out the important information...
>
>
>However, returning to "condense this into a single line", the
>frequently-seen coding is (in my experience, at least):
>
> quantity = float( input( "How many would you like? " ) )
>
>which would not produce the helpful distinction between
>line-numbers/function-calls which the above (better-formatted) code
>does!

Old thread I know, but thought it was worth pointing out that Python 3.11
brought in fine-graned error locations in tracebacks[1]:

$ python3.10 asin.py
Enter a small number: 4
Traceback (most recent call last):
File "/home/p10365088/asin.py", line 3, in <module>
print(math.asin(float(input("Enter a small number: "))))
ValueError: math domain error

$ python3.11 asin.py
Enter a small number: 4
Traceback (most recent call last):
File "/home/p10365088/asin.py", line 3, in <module>
print(math.asin(float(input("Enter a small number: "))))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: math domain error

[1]: https://docs.python.org/3/whatsnew/3.11.html#whatsnew311-pep657

Regards,
Simon
--
A complex system that works is invariably found to have evolved from a
simple system that works.—John Gall
--
https://mail.python.org/mailman/listinfo/python-list