Easy function, please help.

Ethan Furman ethan at stoneleaf.us
Thu Feb 10 17:52:38 CET 2011

Jason Swails wrote:
> On Wed, Feb 9, 2011 at 8:16 PM, Ethan Furman wrote:
>     while n:  is plenty readable.  n is either something or nothing, and
>     something evaluates to True, nothing to False.
> Sure it's readable.  But then you have to make sure that the loop will 
> eventually take n down to 0.  

Sure, but the same holds true with 'while n != 0' -- you have to make 
sure the loop will eventually take n down to 0.

> You can always *assume* that the 
> programmer knew what they were doing (not an assumption I'm typically 
> willing to make on code that's not my own).

Hopefully not something you have to deal with unless you're debugging...

> How is "while n != 0:" any worse?  (or abs(n) < tolerance).  It has 
> exactly the same effect without adding any code while at the same time 
> directly communicates the intended conditional.  IMO it makes reading 
> the code easier to read barring effective documentation (my experience 
> with people documenting their code is that they don't; at least in my 
> field).  "while n != 0" makes my life easier.

In that instance (a bunch of mathematical functions), I can easily see 
using that construct.

> The fact that the proposed loop finished with *nothing* was 
> coincidental.  What if he had been doing some type of prime 
> factorization or something where each iteration reduced the number until 
> eventually all you were left with was the multiplicative identity?  
> You'd say (correctly) that obviously the same approach won't work, but 
> in some lines of thought it's a logical extension to use the same 
> construct (especially to those that don't fully understand why the 
> original loop exits in the first place).  Expanding the conditional a 
> little can only help IMO.

Thank you for making my argument for me -- you have to understand the 
tool you are using to make the best use of it.

>         def num_digits(n):
>           return len(str(n).replace('-','').replace('.',''))
>         Or typecast to an int if you want to neglect decimals before
>         converting to a string, etc.
>         Or use recursion!
>          >>> def num_digits(n):
>         ...    if n == 0:
>         ...       return 0
>         ...    else:
>         ...       return num_digits(n//10) + 1
>         ...
>          >>> num_digits(1)
>         1
>          >>> num_digits(0)
>         0
>     0 is still one digit.  ;)
> Well that is something; yet only nothing evaluates to False.  We seem to 
> be at an impasse :).

I fail to see how a faulty algorithm puts us at an impasse.  To tweak 
your code:

--> def num_digits(n, _first_pass=True):
-->     if n == 0:
-->         return int(_first_pass)
-->     else:
-->         return num_digits(n//10, _first_pass=False) + 1

correctly handles the special case of zero.  To use my style, it would 
look like:

--> def num_digits(n, _first_pass=True):
-->     if n:
-->         return num_digits(n//10, _first_pass=False) + 1
-->     else:
-->         return int(_first_pass)

And, of course, this only works for non-negative integers.  (I'll leave 
the discussion of whether zero is non-negative to others.  ;)  As I said 
earlier, I can see using the 'if n == 0' construct in certain 
situations, and if the non-zero branch were lengthy I would stick with 
the first version here.


More information about the Python-list mailing list