3

Someone came with this example to me (python2):

num = int(input("num")) 
den = int(input("den"))

quot = 0
rest = den
i = num

for i in range(i,i>den, -den):
  quot = quot + 1
  rest = i - den

print quot
print rest     

The code runs fine, does what it needs to be doing, and doesn't produce errors.

I don't understand why. To me, range() requires a lower and an upper limit, and to me, i would be the lower value, while i>den should evaluate to a boolean?

The context is a tutorial function which implements division with a for loop.

transient_loop
  • 5,984
  • 15
  • 58
  • 117
  • can you add a bit more of the surrounding code? as written we don't know all the preconditions (like the initial values of `i` and `num`). – aruisdante Mar 09 '15 at 01:33
  • You can have a condition in a for loop but not a range function. – Malik Brahimi Mar 09 '15 at 01:34
  • @MalikBrahimi No, you can, because `True` evaluates to `1` and `False` to `0`. But it certainly wouldn't behave like a C-like's `for` statement. It's just setting the stop point of iteration to either `0` or `1`. – aruisdante Mar 09 '15 at 01:35
  • Yes, I meant for the intended purpose. – Malik Brahimi Mar 09 '15 at 01:36
  • 1
    Looks to me that whoever wrote this code got Python for-loop syntax mixed up with the for-loop syntax in C, Java, JS, etc. Even if it is technically correct, it is absolutely not pythonic. – pzp Mar 09 '15 at 01:50

2 Answers2

3

This is an application of "duck typing". In this case, i>num evaluates to a boolean value of True or False, but in the context of the range function, True is equivalent to the integer 1, and False is equivalent to the integer 0.

So, for example, if i>num is False, then that code is equivalent to

for i in range(i, 0, -num):
  #do stuff
Brionius
  • 13,858
  • 3
  • 38
  • 49
  • Having said that, there is almost certainly a more clear way to write out the conditions for the iteration than using a clever trick like this, which in Python 2.X is technically relying on an implementation detail. – aruisdante Mar 09 '15 at 01:37
  • For sure - it's a weird bit of code, and not one I'd care to debug or maintain. – Brionius Mar 09 '15 at 01:39
  • Gah, seeing the OP's update it's even crazier, since `i = num` entering the loop so it will *always* be `False`. WTF? – aruisdante Mar 09 '15 at 01:41
  • The update opened my eyes: as i gets initialized to num, then the condition i > num evaluates to True. The range(i, True) evaluates to for example (16, 1), which is an empty range []. BUT, as we have the step change -dev, if dev is 2 for example, the range results in [16, 14, 12, 10, 8, 6, 4, 2] and that's why the code does what it needs to do! – transient_loop Mar 09 '15 at 02:37
  • @aruisdante What implementation detail? – Veedrac Mar 09 '15 at 10:13
  • @Veedrac in Python 2.X, boolean values are not *guaranteed* to be `0,1` when converted to int. This is simply their default. In Python 3.X, the language was changed to guarantee this conversion. See the question that @thedayturns linked to in his answer. – aruisdante Mar 09 '15 at 16:44
  • @faboolous `i > num` is always `False` for `i == num` ;) My guess is that the intention was to effectively remove an iteration for `i > num` if the preconditions were different. It's a "clever" trick, but in python clever is usually considered bad when it hampers clarity and readability. – aruisdante Mar 09 '15 at 16:48
  • @aruisdante Would you then say `int(1.0)` is an implementation detail because someone can reassign `int`? – Veedrac Mar 09 '15 at 19:08
  • @Veedrac No. The problem isn't that `bool()` can be reassigned, it's that `True` and `False` can, and their definition isn't codified in pre-3.X python. In fact `True` need not even be 1 to be compatible with languages like C, it need only be not-zero. Hence why in 2.X it's an implementation detail, where as in 3.X it's guaranteed by the language to be so as `True` and `False` are promoted to keywords rather than special constants. – aruisdante Mar 09 '15 at 20:20
  • @aruisdante What's the difference between reassigning `True` and reassigning `int`? Also, the builtin values for `True` and `False` *are* defined as `1` and `0`: https://docs.python.org/2/library/stdtypes.html#boolean-values. – Veedrac Mar 09 '15 at 20:46
2

This is because Python considers True == 1 and False == 0.

See here for more information: Is False == 0 and True == 1 in Python an implementation detail or is it guaranteed by the language?

Community
  • 1
  • 1
thedayturns
  • 9,723
  • 5
  • 33
  • 41