[Tutor] use of assignment expression
Manprit Singh
manpritsinghece at gmail.com
Mon Aug 17 02:01:46 EDT 2020
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