0
\$\begingroup\$

This function outputs random values in a list. Although I was happy to craft this solution from a more complex version, and it looks really cool to me, I wonder if it is an example of clean code.

How can it be improved, and what are other ways to write it?

def random_time_values() -> List[int]:
    ''' Generates random [hours, minutes, seconds] '''
    return [randint(*time) for time in [(0, 11), (0, 59), (0, 59)]]
\$\endgroup\$
2
  • 3
    \$\begingroup\$ Why are hours limited to 12 not 24 hours? Are you aware of leap seconds, which allow the seconds to become 60. Is the exclusion of leap seconds intentional? In other words I'm asking why does the code exist, so we can better say if your code is a good fit for the situation at hand. \$\endgroup\$
    – Peilonrayz
    Nov 16 at 20:47
  • \$\begingroup\$ @Peilonrayz this function is for an analogue clock validation exercise. The user is asked to validate at what time values the clock hands show. The values are used to calculate clock hands angles and to be compared against user_time = input_field.get() % 12. I think for hour hands angles, only 12 hour fractions are relevant. The user can input 24 hours and the modulo makes it into 12 hour range before comparing values. \$\endgroup\$
    – atlvd
    Nov 17 at 7:44

1 Answer 1

3
\$\begingroup\$

What you've described and what you've written are two different things. You've described a function that outputs random times in a list, but it actually outputs a list of hour-minute tuple values randomly selected from a small, fixed set. Those can't both be true, so let's choose one - your description, of generating random times.

Why not:

  • write a generator function that doesn't take an opinion on how many outputs you want; that way it can generate them lazily and the consumer can use e.g. islice
  • make truly random times, with random hour, minute, second and microsecond fields, rather than choosing from a set

This could be as simple as:

import datetime
import random
from itertools import islice
from typing import Iterator


def random_time_values() -> Iterator[datetime.time]:
    base = datetime.datetime(1, 1, 1)
    while True:
        delta = datetime.timedelta(days=random.random())
        yield (base + delta).time()


def demo(n: int = 25) -> None:
    for t in islice(random_time_values(), n):
        print(t)


if __name__ == '__main__':
    demo()
22:09:36.696135
11:23:34.522248
00:09:56.177813
05:24:03.343375
22:25:56.346006
03:48:09.863071
20:48:27.955984
18:06:57.958131
00:15:05.198247
04:12:29.939244
09:50:25.152160
17:16:13.000451
10:51:36.054653
20:21:09.080549
02:00:15.132786
20:53:58.105197
08:25:13.088035
17:01:38.471288
04:14:28.054855
12:39:29.076931
07:13:03.665626
19:23:39.066675
15:46:20.652315
14:34:02.837399
13:34:33.400851
\$\endgroup\$
3
  • \$\begingroup\$ I didn't realise datetime values could be generated, I thought of the values as fractions of the circle: 12 parts and 60 parts of a whole. Thank you @Reinderien Although the function does return a list of three integer values, I understand now that these values are not explicit time values: >>> [randint(*time) for time in [(0, 11), (0, 59), (0, 59)]] # [7, 48, 19] \$\endgroup\$
    – atlvd
    Nov 17 at 7:46
  • \$\begingroup\$ After learning a bit about datetime this solution occured to me: random_time: datetime=datetime.time(randint(0, 23), randint(0, 59), randint(0, 59)) \$\endgroup\$
    – atlvd
    Nov 19 at 19:25
  • 1
    \$\begingroup\$ That's both more complicated and not as random, since it doesn't set microseconds. \$\endgroup\$
    – Reinderien
    Nov 19 at 19:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.