Будильник подкласс часов

У меня есть эти два класса, и они должны оставаться отдельными классами, но я чувствую, что это можно было бы реализовать более эффективно и с меньшим количеством повторяющегося кода. После того, как я погуглил, я все еще не нашел лучшего способа, так что, возможно, кто-то здесь может указать мне. В идеале я хочу получить метод tick () от Clock и просто добавить к нему будильник, а также получить метод set_time () с дополнительными атрибутами для установки времени будильника.

class Clock:

def __init__(self, hours, minutes, seconds):
    self.set_time(hours, minutes, seconds)

def set_time(self, hours, minutes, seconds):
    if hours < 0:
        self.hours = 0
    elif hours > 23:
        self.hours = 23
    else:
        self.hours = hours

    if minutes < 0:
        self.minutes = 0
    elif minutes > 59:
        self.minutes = 59
    else:
        self.minutes = minutes

    if seconds < 0:
        self.seconds = 0
    elif seconds > 59:
        self.seconds = 59
    else:
        self.seconds = seconds

def tick(self):
    while True:
        print(str(self.hours).zfill(2), ":", str(self.minutes).zfill(2), ":", str(self.seconds).zfill(2), sep="")
        self.seconds += 1
        time.sleep(1)
        if self.seconds == 60:
            self.seconds = 0
            self.minutes += 1
            if self.minutes == 60:
                self.minutes = 0
                self.hours += 1
                if self.hours == 24:
                    self.hours = 0


class AlarmClock(Clock):

def __init__(self, hours, minutes, seconds, alarm_hr, alarm_min, alarm_sec):
    super().__init__(hours, minutes, seconds)
    self.set_alarm(alarm_hr, alarm_min, alarm_sec)

def set_alarm(self, alarm_hr, alarm_min, alarm_sec):
    if alarm_hr < 0:
        self.alarm_hr = 0
    elif alarm_hr > 23:
        self.alarm_hr = 23
    else:
        self.alarm_hr = alarm_hr

    if alarm_min < 0:
        self.alarm_min = 0
    elif alarm_min > 59:
        self.alarm_min = 59
    else:
        self.alarm_min = alarm_min

    if alarm_sec < 0:
        self.alarm_sec = 0
    elif alarm_sec > 59:
        self.alarm_sec = 59
    else:
        self.alarm_sec = alarm_sec

def alarm(self):
    while True:
        print(str(self.hours).zfill(2), ":", str(self.minutes).zfill(2), ":", str(self.seconds).zfill(2), sep="")
        self.seconds += 1
        time.sleep(1)
        if self.seconds == 60:
            self.seconds = 0
            self.minutes += 1
            if self.minutes == 60:
                self.minutes = 0
                self.hours += 1
                if self.hours == 24:
                    self.hours = 0
        if self.hours == self.alarm_hr and self.minutes == self.alarm_min and self.seconds == self.alarm_sec:
            print("ALARM ALARM ALARM ALARM ALARM!!!!")
            break

2 ответа
2

Я реорганизовал часть вашего кода, обратите внимание, что я игнорирую уже существующие библиотеки, так как предполагаю, что существует конкретная причина (образовательная или иная), стоящая за внедрением Clock, tickи т. д. таким образом самостоятельно.

класс Часы:

class Clock:
    def __init__(self, hours: int, minutes: int, seconds: int):
        self.hours = self.normalize_time_in_range(hours, 0, 23)
        self.minutes = self.normalize_time_in_range(minutes, 0, 59)
        self.seconds = self.normalize_time_in_range(seconds, 0, 59)

    @staticmethod
    def normalize_time_in_range(value: int, lower_bound: int, upper_bound: int) -> int:
        if value < lower_bound:
            return lower_bound
        elif value > upper_bound:
            return upper_bound
        else:
            return value

    def start_ticking(self):
        while True:
            self.tick()

    def tick(self):
        print(f"{str(self.hours).zfill(2)}:{str(self.minutes).zfill(2)}:{str(self.seconds).zfill(2)}")
        self.seconds += 1
        time.sleep(1)
        if self.seconds == 60:
            self.seconds = 0
            self.minutes += 1
            if self.minutes == 60:
                self.minutes = 0
                self.hours += 1
                if self.hours == 24:
                    self.hours = 0
  1. normalize_value_in_range: Обратите внимание, что у вас много дублированной логики в set_time и set_alarm. Большая часть логики может быть извлечена из этой более общей реализации.
  2. start_ticking и отметьте: В вашем случае я счел полезным отделить цикл от фактической логики тиков, чтобы вы могли изменять условия цикла в подклассах при повторном использовании tick. Вы увидите, почему это полезно в AlarmClock.
  3. Аннотации типов: Как вы можете видеть в заголовках методов, я добавил несколько подсказок по типам для вновь добавленных методов. Как правило, это хорошая идея для документирования кода для себя и других.

класс AlarmClock:

class AlarmClock(Clock):
    def __init__(self, hours, minutes, seconds, alarm_hr, alarm_min, alarm_sec):
        super().__init__(hours, minutes, seconds)

        self.alarm_hr = self.normalize_value_in_range(alarm_hr, 0, 23)
        self.alarm_min = self.normalize_value_in_range(alarm_min, 0, 59)
        self.alarm_sec = self.normalize_value_in_range(alarm_sec, 0, 59)

        self.ticking = False

    def start_ticking(self):
        self.ticking = True
        while self.ticking:
            self.tick()

    def tick(self):
        super().tick()
        if self.hours == self.alarm_hr and self.minutes == self.alarm_min and self.seconds == self.alarm_sec:
            print("ALARM ALARM ALARM ALARM ALARM!!!!")
            self.ticking = False
  1. normalize_value_in_range: Теперь мы можем повторно использовать этот метод для установки времени будильника.
  2. start_ticking и отметьте: Поскольку мы отделили цикл от фактического тика, мы можем использовать Clock.tick() в нашем AlarmClock без необходимости дублировать код. Добавление атрибута self.ticking к AlarmClock позволяет нам выйти из цикла между методами. Причина, по которой мы не могли повторно использовать tick() раньше было потому, что он содержал бесконечное while True цикл, тем самым не позволяя нам перехватывать, когда достигается alarm_time.

время учебы:
Наконец, я бы предложил отделить логику времени от логики часов. Это делает часы более лаконичными и позволяет расширить функциональность Time класс по мере необходимости. Можно также сказать, что это позволяет часам сосредоточиться на их основных функциях. Опять же, я игнорирую существование библиотек для этой задачи, поскольку предполагаю, что вы хотите реализовать всю логику самостоятельно. Специализированные библиотеки, такие как datetime заслуживают внимания, поскольку они обеспечивают множество удобных функций. Одна реализация может быть следующей:

class Time:
    def __init__(self, hours: int, minutes: int, seconds: int):
        self.hours = self.normalize_value_in_range(hours, 0, 23)
        self.minutes = self.normalize_value_in_range(minutes, 0, 59)
        self.seconds = self.normalize_value_in_range(seconds, 0, 59)

    @staticmethod
    def normalize_value_in_range(value: int, lower_bound: int, upper_bound: int) -> int:
        if value < lower_bound:
            return lower_bound
        elif value > upper_bound:
            return upper_bound
        else:
            return value

    def increment(self):
        self.seconds += 1
        if self.seconds == 60:
            self.seconds = 0
            self.minutes += 1
            if self.minutes == 60:
                self.minutes = 0
                self.hours += 1
                if self.hours == 24:
                    self.hours = 0

    def __eq__(self, other):
        return self.hours == other.hours and self.minutes == other.minutes and self.seconds == other.seconds

    def __str__(self):
        return f"{str(self.hours).zfill(2)}:{str(self.minutes).zfill(2)}:{str(self.seconds).zfill(2)}"


class Clock:
    def __init__(self, hours: int, minutes: int, seconds: int):
        self.time = Time(hours, minutes, seconds)

    def start_ticking(self):
        while True:
            self.tick()

    def tick(self):
        print(self.time)
        self.time.increment()
        time.sleep(1)


class AlarmClock(Clock):
    def __init__(self, hours, minutes, seconds, alarm_hr, alarm_min, alarm_sec):
        super().__init__(hours, minutes, seconds)
        self.alarm_time = Time(alarm_hr, alarm_min, alarm_sec)

        self.ticking = False

    def start_ticking(self):
        self.ticking = True
        while self.ticking:
            self.tick()

    def tick(self):
        super().tick()
        if self.time == self.alarm_time:
            print("ALARM ALARM ALARM ALARM ALARM!!!!")
            self.ticking = False

    Ваш проект является хорошей иллюстрацией общего принципа написания программного обеспечения: внутреннее хранилище данных (например, как класс Clock отслеживает время) и внешнее представление (например, как время должно быть напечатано для пользователя) — это два разные вещи.

    Ваш код можно значительно упростить, сохранив данные в самом простом возможном формате: всего в секундах. Только когда это необходимо для пользы пользователей, вы беспокоитесь о том, чтобы собрать время в HH:MM:SS формат. Если мы воспользуемся этим подходом, вам понадобится метод для преобразования часов, минут, секунд в общее количество секунд. И нам также нужен способ конвертировать другое направление. Для краткости здесь я игнорирую валидацию:

    import time
    
    class Clock:
    
        def __init__(self, hours, minutes, seconds):
            # Just store total seconds.
            self.total_secs = self.hms_to_seconds(hours, minutes, seconds)
    
        def hms_to_seconds(self, hours, minutes, seconds):
            # Simple converter.
            return hours * 3600 + minutes * 60 + seconds
    
        # Properties to retrieve user-facing values when needed.
    
        @property
        def hours(self):
            return self.total_secs // 3600
    
        @property
        def minutes(self):
            return (self.total_secs - (3600 * self.hours)) // 60
    
        @property
        def seconds(self):
            return self.total_secs - 3600 * self.hours - 60 * self.minutes
    
        def tick(self):
            # Make tick do less, so you can re-use it.
            print(f'{self.hours:>02}:{self.minutes:>02}:{self.seconds:>02}')
            self.total_secs += 1
            time.sleep(1)
    
        def run(self):
            # A basic clock just ticks forever.
            while True:
                self.tick()
    
    class AlarmClock(Clock):
    
        def __init__(self, hours, minutes, seconds, alarm_hr, alarm_min, alarm_sec):
            super().__init__(hours, minutes, seconds)
            self.alarm_secs = self.hms_to_seconds(alarm_hr, alarm_min, alarm_sec)
    
        def run(self):
            # An alarm clock ticks and alarms.
            while True:
                self.tick()
                if self.total_secs >= self.alarm_secs:
                    print("ALARM ALARM ALARM ALARM ALARM!!!!")
                    break
    
    AlarmClock(1, 15, 0, 1, 15, 5).run()
    

      Добавить комментарий

      Ваш адрес email не будет опубликован. Обязательные поля помечены *