-1

I've been looking at this for awhile and been going through my head on how it works. I know the first part of it but when I get to the counter I get stuck at

    hr, sc = divmod(counter, 3600)
    mn, sc = divmod(sc, 60)

I've looked into divmod() but I am still confused on what it actually does. And why does sc work here when it isn't defined anywhere else?

To summarize:

1: What is divemod() 2: What does the above code do in the below countdown timer and how does it do it?

hours= int(input("Hours: "))
minutes= int(input("Minutes: "))
sec= int(input("Seconds: "))

counter=hours*3600+minutes*60+sec
mins=int(counter/60)
hr=int(mins/60)

while counter > 0:
    counter-=1
    hr, sc = divmod(counter, 3600)
    mn, sc = divmod(sc, 60)
    print ('%d hours, %d minutes and %d seconds' % (hr, mn, sc))
    mins=int(counter/60)
    hr=int(mins/60)
    time.sleep(1)

Thanks!

  • Hint: `divmod` performs division on two numbers, and returns the quotient and remainder. – Kevin Sep 19 '14 at 19:29
  • 1
    What do you mean by `And why does sc work here when it isn't defined anywhere else?`? `sc` is defined in the line `hr, sc = divmod(counter, 3600)`. That line is defining two variables. Does that make it make more sense? – David Robinson Sep 19 '14 at 19:29
  • Is it just the syntax where you have two variables on the left side? Those are just matched to the two on the right side of the equals sign. – Ulrich Eckhardt Sep 19 '14 at 19:29
  • Meta-hint: you can determine what a function does by entering `help(functionname)` into the interactive interpreter. – Kevin Sep 19 '14 at 19:30
  • Hmm I see. I didn't realize that you can define 2 variables on the same line. So `hr, sc = divmod(counter, 3600)` is dividing the total of the counter by 3600 and throughing the values in `hr` and `sc`? – user3763447 Sep 19 '14 at 19:31
  • 1
    Related: [What is the name of a `[foo, bar] = [“foo”, “bar”]` feature?](http://stackoverflow.com/questions/3951946/what-is-the-name-of-a-foo-bar-foo-bar-feature) – Jonathan Lonowski Sep 19 '14 at 19:31
  • I will read that, Jonathan. – user3763447 Sep 19 '14 at 19:33
  • 1
    @user3763447: That is called "tuple unpacking". You can read more in the [tutorial](https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences). – Matthias Sep 19 '14 at 19:42

1 Answers1

2

Divmod is a function that performs a division and returns two values, the integer quotient and the remainder. It technically returns a two number tuple and that gets unpacked into the two variables.

For example, divmod(10, 3) returns (3, 1), where 3 is the result of 10 / 3 and 1 is the result of 10 % 3 (10 mod 3).

Saying a, b = divmod(10, 3) is the equivalent of a, b = (3, 1) which assigns 3 to a and 1 to b.

In the case of the timer, this is taking a value of seconds and breaking out the amount of seconds that correspond to quantities of hours and minutes. Every 3600 seconds is an hour and every 60 seconds (after the hours are subtracted) are minutes.

So, when the number of seconds remaining in the timer is 10,000, the first divmod says, "This is actually 2 hours and 2,800 seconds," and the second divmod, performed on 2,800, says, "That is actually 46 minutes and 40 seconds." Put together, these two lines say "10,000 seconds is actually 2 hours, 46 minutes, and 40 seconds."


Aside 1, the code performing these computations takes non-zero time, so this countdown timer will actually be slower than desired because it takes marginally more than a second to count down each second (it sleeps for a second and then performs some computation).


Aside 2, the code you wrote could be reduced to the following:

hours = int(input("Hours: "))
minutes = int(input("Minutes: "))
seconds = int(input("Seconds: "))

counter = hours*3600 + minutes*60 + seconds

while counter > 0:
    counter -= 1
    hours, seconds = divmod(counter, 3600)
    minutes, seconds = divmod(seconds, 60)
    print('%d hours, %d minutes and %d seconds' % (hours, minutes, seconds))
    time.sleep(1)

Aside 3, beware of the input function. If the user types an expression rather than a number, it is evaluated by the python interpreter. See Is it ever useful to use Python's input over raw_input?

You are already casting the results of input to integers. USE raw_input INSTEAD OF input!!!!! (Unless this is python3, in which case raw_input has been renamed input). For python2, do the following:

hours = int(raw_input("Hours: "))
minutes = int(raw_input("Minutes: "))
seconds = int(raw_input("Seconds: "))
Community
  • 1
  • 1
Zags
  • 37,389
  • 14
  • 105
  • 140
  • Thank you for the insightful answer. It explained everything beautifully. Also, so you're saying this timer will be off by a second? If so do you have an idea of a better timer that prints it out similarly? ex: 1 hour, 20 minutes, 30 seconds – user3763447 Sep 19 '14 at 19:41
  • @user3763447 It's not that it will be off by a second. It's that it will take something like 1.0005 seconds to count down each second (although that number could be very different depending on what system you run on and what else is running). – Zags Sep 19 '14 at 19:46
  • @user3763447 To make an accurate timer, you want to store `timer_start = datetime.datetime.now()` at the beginning of the program and use the difference between the current time and `timer_start` instead of `counter`. Alternatively, the `timeit` library has options other than `datetime`. – Zags Sep 19 '14 at 19:48