[Tutor] use of assignment expression
Manprit Singh
manpritsinghece at gmail.com
Mon Aug 17 03:05:18 EDT 2020
Dear Sir,
My question was about to write a program to find the smallest n digit
number, divisible by number x.
There are now two solutions to this problem:
n = 5
x = 83
no = 10**(n-1)
while True:
if (no / x).is_integer():
print(no)
break
no = no + 1
------------------------------------------------
n = 5
x = 83
no = 10**(n-1)
if no % x == 0:
print(no)
else:
print((no + x) - ((no + x) % x))
Will give the answer 10043. What I have concluded from all the previous
mails, that assignment expression can be avoided in this case .The first
solution is not in more mathematical terms, but the second solution is
more mathematical. Need your comments further.
Regards
Manprit Singh
On Mon, Aug 17, 2020 at 11:31 AM Manprit Singh <manpritsinghece at gmail.com>
wrote:
> Dear all,
>
> Thanks for the response. So If i just say the better, clear and readable
> solution is :
>
> n = 5
> x = 83
> no = 10**(n-1)
> if no % x == 0:
> print(no)
> else:
> print((no + x) - ((no + x) % x))
>
> We can avoid using assignment expression in this example.
>
> Regards
> Manprit Singh
>
>
>
>
> On Mon, Aug 17, 2020 at 10:34 AM dn via Tutor <tutor at python.org> wrote:
>
>> On 17/08/2020 01:55, Manprit Singh wrote:
>> > Dear sir ,
>> > i need a comment on the use of assignment expression in the below given
>> > example :
>> >
>> > # Program to find smallest n digit number divisible by a number x
>> > n = 5
>> > x = 83
>> > if (no := (10**(n-1) % x)) == 0:
>> > print(10**(n-1))
>> > else:
>> > print((mx := (10**(n-1) + x)) - (mx % x))
>> >
>> > The answer is 10043, which is the right answer . Just need to know if
>> the
>> > way of using the assignment expression (2 times in the above example is
>> > efficient or not.),
>> >
>> > What i feel is the usage of assignment expressions is reducing the
>> > readability of the code written above . Need your guidance.
>>
>>
>> Have you read the other responses? Here's an alternate point-of-view:-
>>
>> Firstly, this is an arcane calculation. Whilst it may well reveal the
>> meaning of the universe*, it seems (to me) that the people who talk like
>> this are mathematicians, not (?mere) ordinary folk. Therefore, if the
>> bunch of likely users (or more reasonably: the coders and users likely
>> to ever read/check the code) are happily-capable of keeping stuff like
>> this in their heads, "readability" is in the eye of the beholder! I
>> don't like it. I'd break the formula into components - but I am not that
>> sort of mathematician!
>>
>> Secondly, "efficiency". If we execute this calculation
>> once-in-a-blue-moon*, none of the re-statements proposed will make a
>> noticeable difference. However, ... if this is to become a function
>> which is executed hundreds of times within some larger calculation, eg
>> what will the weather be like tomorrow? or, is there some new/uncharted
>> star in this image of the galaxy? then the question of "efficiency"
>> becomes (that many "hundreds of times") more important! Efficiency is
>> not something to retro-fit. If the application requires efficiency, then
>> it is 'in the spec' from-the-word-go!
>>
>> That said, "readability" is often in a trade-off with efficiency!
>>
>>
>> We were introduced to the word "debuggability". Great choice: "able to
>> be debugged". Let's try making our code 'testable', which puts it on the
>> way to being "provable" (a term in math - just to show that I often talk
>> with mathematicians - some of my best friends are ...). So, following
>> the precepts of TDD (Test-Driven Development*) - which should be
>> enormously popular in the world of mathematical computing (because of
>> its similarity to developing a "proof"), let's start with:-
>>
>> # test_divisor.py
>> import divisor # you'll think of a much more meaningful name!
>> n = 5
>> x = 83
>> assert divisor.divisor( n, x ) == 10043
>> # later add a bunch more tests
>> # especially for the opposite calculation
>> # plus any/all the edge-cases/exceptions you can imagine
>> ...
>>
>> Having written a test, which will fail at the import, let's 'fix' that:
>>
>>
>> Funny ha-ha! Now execution/testing fails at the assert, because there is
>> no such function:-
>>
>> # divisor.py
>> # Program to find smallest n digit number divisible by a number x
>>
>> def divisor( n, x ):
>> if (no := (10**(n-1) % x)) == 0:
>> print(10**(n-1))
>> else:
>> print((mx := (10**(n-1) + x)) - (mx % x))
>>
>> The test fails because the assert 'complains' that returning None is
>> incorrect.
>>
>>
>> Let's pause to discuss "testability". SRP (Single Responsibility
>> Principle) applies - code each function/method to perform one task (and
>> to perform it well). The function as it stands (as directly copied from
>> the OP's code - with due apologies) performs TWO tasks: the calculation,
>> and the printing of its result. Trivial? Agreed! However, principles are
>> principles - and this is a toy-example. If we remove the second task,
>> the function becomes thoroughly 'testable'. It has one task to complete,
>> and we can easily check to see if the task has completed, and has
>> delivered the correct response:-
>>
>> def divisor( n, x ):
>> if (no := (10**(n-1) % x)) == 0:
>> return 10**(n-1)
>> else:
>> return (mx := (10**(n-1) + x)) - (mx % x)
>>
>> Does that first test now work? Yes!
>> (only because our brilliance outshines the sun...)
>>
>> BTW: add an if __main... and print( divisor(...) ) to divisor.py, and
>> you'll be able to see where that second task (printing)
>> currently-belongs - in case you were wondering.
>>
>>
>> One of the other components of TDD is to re-factor (both code-code and
>> test-code). One component of re-factoring is - wait for it -
>> "efficiency". Sure, most of us, happily deciding to use an
>> interpreted-language, don't worry too much about this - but there will
>> still be folks whose eyes start to bulge* at such a blasé assumption -
>> and failure to accommodate (their) "diversity"!
>>
>> Personally, I favor the virtue of putting the base-calculation before
>> the if-statement. However, I'm a simple boy, and thus not a
>> mathematician. If you are, and you are comfortable with reading the
>> expression as a single thought (as are your colleagues) then your
>> opinions of "readability" and "complexity" will be very different from
>> mine! (psychology: "chunking")
>>
>>
>> Having stood-upon principle (SRP) earlier, let's pull out another. How
>> about DRY (Do not Repeat Yourself)? Few coders (judging from the worst
>> of the YouTube demos) are typists - and can I/dare I say, even fewer
>> mathematicians. So, if the expression "10**(n-1)" has to be entered into
>> the code-base three (or more) times, what are the chances of a typo
>> creeping-in somewhere?
>>
>> Talking about "debuggability"? The best debugging is to obviate its
>> need! Quoting some commentary from my over-the-fence conversation with a
>> neighbor this morning: "best to keep your mouth closed and be thought a
>> fool, than to open it and remove all doubt!"* (no he didn't have you (or
>> I) in-mind) Re-stated for our use: 'best not to type, if you don't have
>> to'. Thus: type it once, make it test-able, test it, and then re-use
>> with confidence!
>>
>>
>> The time has come, to talk about the walrus (with apologies to Lewis
>> Carroll*). An <<<assignment expression (sometimes also called a “named
>> expression” or “walrus”) assigns an expression to an identifier, while
>> also returning the value of the expression.>>>* The PEP's rationale,
>> better-explains its advantages/purposes as <<<Naming the result of an
>> expression is an important part of programming, allowing a descriptive
>> name to be used in place of a longer expression, and permitting reuse.>>>*
>>
>> There's that "re-use" again - and my DRY sense of humor. Hah!
>>
>> The OP twice demonstrates the named-expression's syntax but in the first
>> case, sadly, fails to benefit from its purpose (as observed in another
>> response). The "reuse" advantage/rationale was lost.
>>
>> Which part(s) of the calculations are candidates for reuse? Well,
>> "10**(n-1)" appears three times. So let's start there. I would go for:
>>
>> n_digit_number = 10**(n-1)
>> if...
>>
>> but, in-keeping with the OP's (apparent) preferences, the
>> all-in-one/walrus approach is:
>>
>> if ( (no := 10**(n-1) ) % x) == 0:
>>
>> NB only a mathematician could love a variable called "no". Do I like it?
>> No! Do I (primarily) speak a language where the word "number" includes
>> the letters "N" and "o". No! 98% of Norwegians likely also agree.
>>
>>
>> TDD-ers: run a test to assure the refactoring work! Then we can move-on
>> to:-
>>
>> if...
>> return no # saving one re-computation
>> else:
>> return (mx := no + x) - (mx % x))
>> # the use of no saving another re-computation, plus
>> # using mx already demonstrates how it should be done!
>>
>> Get your TDD-on, and ensure that this is correct...
>>
>>
>> There is no point in using a named-assignment if it is not subsequently
>> re-used - any more than would be the case for other types of assignment.
>> Conversely, if the same computation is required at multiple points in
>> the code, then the 'walrus operator' is another arrow in your quiver*.
>>
>>
>> NB I'm not running Python v3.8. Accordingly have yet to build-up an
>> opinion based upon experience!
>>
>>
>> Web.Refs
>> apologies, not Monty Python: https://en.wikipedia.org/wiki/42_(number)
>>
>> https://www.dictionary.com/browse/once-in-a-blue-moon
>>
>>
>> https://www.agilealliance.org/glossary/tdd/#q=~(infinite~false~filters~(postType~(~'page~'post~'aa_book~'aa_event_session~'aa_experience_report~'aa_glossary~'aa_research_paper~'aa_video)~tags~(~'tdd))~searchTerm~'~sort~false~sortDirection~'asc~page~1)
>>
>> Surprise!
>> https://image.shutterstock.com/image-photo/image-450w-228517990.jpg
>>
>>
>> https://www.quora.com/What-does-the-phrase-open-your-mouth-and-remove-all-doubt-mean?share=1
>>
>> https://forum.wordreference.com/threads/stand-on-principle.2206751/
>>
>>
>> https://www.goodreads.com/quotes/6028-the-time-has-come-the-walrus-said-to-talk-of
>>
>> https://docs.python.org/3/whatsnew/3.8.html#assignment-expressions
>>
>> https://docs.python.org/3/reference/expressions.html?highlight=named%20expressions#assignment-expressions
>> https://www.python.org/dev/peps/pep-0572/
>>
>> https://idioms.thefreedictionary.com/an+arrow+in+the+quiver
>> --
>> Regards =dn
>> _______________________________________________
>> Tutor maillist - Tutor at python.org
>> To unsubscribe or change subscription options:
>> https://mail.python.org/mailman/listinfo/tutor
>>
>
More information about the Tutor
mailing list