I am new to learning python, I have been using source material for inspiration on how to code an alarm clock. I was wondering if anyone could explain a couple of the lines for me?
print("Set a time for the alarm (Ex. 06:30 or 18:30:00)")
while True:
alarm_input = input(">> ")
try:
alarm_time = [int(n) for n in alarm_input.split(":")]
if check_alarm_input(alarm_time):
break
else:
raise ValueError
except ValueError:
print("ERROR: Enter time in HH:MM or HH:MM:SS format")
# Convert the alarm time from [H:M] or [H:M:S] to seconds
seconds_hms = [3600, 60, 1] # Number of seconds in an Hour, Minute, and Second
alarm_seconds = sum(
[a*b for a, b in zip(seconds_hms[:len(alarm_time)], alarm_time)])
The while True is just referring to the check_alarm_input function I have which makes sure that the input is an actual time.
I am mainly confused by the line converting the alarm time to seconds,
I am not sure what a and b is and what is the purpose of the colon in:
zip(seconds_hms[:len(alarm_time)]
Any help appreciated!
CodePudding user response:
Let's say the user inputs the string "1:20:45"
.
Then, the alarm_time
list will be [1, 20, 45]
.
The seconds_hms
will of course always be [3600, 60, 1]
.
Next, let's look at seconds_hms[:len(alarm_time)]
.
len(alarm_time)
is 3
in this example, so this is equivalent to seconds_hms[:3]
.
This is a slicing operation, which slices the seconds_hms
list from index 0
implicitly, and slices up to (but not including) index 3
, which would be the fourth item, and then returns the new sliced list. In this case, the sliced list is the same as the unsliced list [3600, 60, 1]
. If the user had entered the string "1:20"
, then len(alarm_time)
would be 2
, which means the slice would be from 0
to 2
(not including index 2
), which means the sliced list would be [3600, 60]
.
Going back to my original example, what we have now is equivalent to zip([3600, 60, 1], [1, 20, 45])
. zip
will yield tuples that contain the next item from each iterable. So, the first tuple will be (3600, 1)
, the second tuple will be (60, 20)
, and the third tuple will be (1, 45)
.
These tuples are then unpacked into a
and b
in the list-comprehension. So, during the first iteration, a
will be 3600
and b
will be 1
. During the second iteration, a
will be 60
and b
will be 20
. In the third iteration a
will be 1
and b
will be 45
.
Essentially, the list comprehension is constructing a list that looks like: [3600 * 1, 60 * 20, 1 * 45]
.
Which is equivalent to: [3600, 1200, 45]
.
You then take the sum of that list to get 4845
seconds.
If the user had entered 1:20
instead of 1:20:45
, like I mentioned earlier, then len(alarm_time)
would be 2
instead of 3
. This means the sliced list we pass to zip
would be shorter:
zip([3600, 60], [1, 20])
Which means zip
would only yield two tuples, which means our list-comprehension would only have two iterations, and the constructed list would only have two values:
[3600 * 1, 60 * 20]
.
That being said, the slicing operationg is not required, since zip
will stop yielding tuples as soon as one of its iterables is exhausted. That means you can simply write: zip(seconds_hms, alarm_time)
, and your script should behave exactly the same way.