LINUX.ORG.RU

Класс-счётчик времени

 , ,


0

2

Всем привет. Возник ещё один нубский вопрос про Python. Хочу сделать следующее: 1)создать свой класс вроде class MyTime(datetime.datetime); 2)написать в нём метод, чтобы выводил текущее значение в нужном мне виде; 3)написать в нём метод, чтобы увеличивал текущее значение на заданную datetime.timedelta в зависимости от аргумента.

И вот если первые две задачки не вызывают вопросов, то третья вызывает ещё как. По self собственное значение экземпляра не изменишь, как я уже понял из мануала. Поля у datetime.datetime не writeable, увы. Можно было бы сделать эту переменную глобальной, а функции написать «россыпью», но логичнее всё это объединить в класс, нет?

а в атрибут значение если сохранять ?

bryak ★★★★
()

class MyTime(datetime.datetime)

Проще будет не наследоваться от datetime.datetime, а написать класс-обёртку, который сохраняет в переменную заданное значение, а при необходимости его изменить, обновляет это значение.

class MyTime:
    def __init__(self, date):
        self._date = date

    def get_formatted_date(self):
        """Или можно переопределить __repr__ и __str__"""
        return self._date.strftime('...')

    def update_date(self, delta):
        """Можно перегрузить сложение"""
        self._date += delta
grazor ★★
()
Ответ на: комментарий от grazor

который сохраняет в переменную заданное значение

Не в переменную, а в атрибут.

bryak ★★★★
()
Ответ на: комментарий от grazor

написать класс-обёртку

Вот я думал над этим, но не дошёл до решения.

self._date = date

Это чтобы потом объявлять, например, today = MyTime(datetime.datetime(2000, 1, 1, 0, 0))?

self._date += delta

delta — это должна быть datetime.timedelta. Интересно, не получится ли при сложении опять datetime.datetime. Хотя не, не должно, вчера я такое получил, действуя по-другому.

al_exquemelin ★★★
() автор топика

но логичнее всё это объединить в класс
По self собственное значение экземпляра не изменишь

ООП головного мозга с тяжелой формой мутабельного аффекта.

Олсо http://xyproblem.info/

anonymous
()
Ответ на: комментарий от anonymous

Да, я считаю, что методы и значение удобнее объединить в одну сущность, чем оставить их лежать в «корне» модуля. Нелогично делать класс, которому будет принадлежать только один уникальный экземпляр, но тем не менее.

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от al_exquemelin

Да, я считаю, что методы и значение удобнее объединить в одну сущность, чем оставить их лежать в «корне» модуля.

Зачем делать дополнительный неймспейс?

Нелогично делать класс, которому будет принадлежать только один уникальный экземпляр, но тем не менее.

Бинго!

Ты лучше скажи зачем тебе MyTime, возможно тупой __add__ решит проблему.

anonymous
()
Ответ на: комментарий от anonymous

Зачем делать дополнительный неймспейс?

Написал же:

методы и значение удобнее объединить в одну сущность

зачем тебе MyTime, возможно тупой __add__ решит проблему

Не решит, там ещё вывод значения не по правилам strftime.

al_exquemelin ★★★
() автор топика

Тред не читал

import datetime

class CustomDate(object):
    def __init__(self, date):
        self._date = date

    def __str__(self):
        return self._date.strftime('%d-%m-%Y')

    def inc(self, delta):
        self._date += delta


if __name__ == '__main__':
    cd = CustomDate(datetime.datetime.now())
    print(cd)
    cd .inc(datetime.timedelta(days=1))
    print(cd)

31-05-2017
01-06-2017
vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 1)
Ответ на: комментарий от al_exquemelin

Не решит, там ещё вывод значения не по правилам strftime.

То есть мы решаем проблему, про которую ты нам ничего не скажешь? Классическая клиника)

anonymous
()

3)написать в нём метод, чтобы увеличивал текущее значение на заданную datetime.timedelta в зависимости от аргумента.

Сделай, чтобы метод не увеличивал текущее значение, а возвращал новый объект с увеличенным значением. Так работают с иммутабельными вещами.

goingUp ★★★★★
()
Ответ на: комментарий от anonymous

Я в первом посте кому написал вот это?

2)написать в нём метод, чтобы выводил текущее значение в нужном мне виде
первые две задачки не вызывают вопросов

Брысь, короче говоря.

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от goingUp

Пробовал сделать что-то в этом духе, но возвращалось datetime.datetime. Надо было ещё раз преобразовывать к моему классу, видимо.

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от al_exquemelin

Я в первом посте кому написал вот это?

Ты про Y написал, какой там X только ТНБ ведает)

Хинт: форматирование даты должно происходить в самом внешнем слое приложения, поэтому никакого MyDate не нужно изначально и хватит strftime.

anonymous
()
Ответ на: комментарий от anonymous

и хватит strftime

И как ты превратишь «15 Май 2017» в «15 мая 2017», а «00:00», например, в «полночь»? Нет, нужна ещё функция, а её логично как раз запихать внутрь той сущности, которая хранит время.

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от al_exquemelin

И как ты превратишь «15 Май 2017» в «15 мая 2017», а «00:00», например, в «полночь»?

Я так и знал))

Нет, нужна ещё функция, а её логично как раз запихать внутрь той сущности, которая хранит время.

Логично ее сделать именно функцией так как это всего-лишь презентация и никакого отношения к объекту дата-время она не имеет. Ей же не нужно приватных полей? Презентаций много, а сущность одна, не так ли?

И неужели ты всерьез считаешь, что от записи obj.method(), method(obj) или даже (method obj) что-то меняется? Молодо зелено. Может тебя еще корежит что len() это функция, а ведь это не ООП? От перемены мест слагаемых ничего не меняется, роляют только связанность и сцепленность. Форматирование даты юзает только публичный интерфейс stdlib, поэтому сцеплено минимально и может быть где-угодно и чем угодно.

anonymous
()
Ответ на: комментарий от anonymous

никакого отношения к объекту дата-время она не имеет

Здрасьте, не имеет. Она обрабатывает именно этот объект и только его.

от записи obj.method(), method(obj) или даже (method obj) что-то меняется

Ну, это смотря где функция определена, нет?

len() это функция

Вот только len() работает со всем подряд, а моя функция — только в пределах одного объекта.

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от al_exquemelin

Вот только len() работает со всем подряд

Со всем что имеет __len__.

а моя функция — только в пределах одного объекта.

Со всем подряд, что имеет year, month, day...

Но ты можешь и дальше продолжать плодить классы, вместо того чтобы решать конкретные проблемы, это тоже полезно в какой-то мере)

anonymous
()
Ответ на: комментарий от anonymous

Ну и напоследок, тебе не кажется странным, то что из-за достаточно тривиальной задачи по форматированию даты ты еще вдогонку хочешь писать код по мутированию данных, чтобы везде были «хорошие» объекты? Это пахнет говном и тупостью.

anonymous
()
Ответ на: комментарий от anonymous

Со всем подряд, что имеет year, month, day...

Там будет только один такой объект, скорее всего.

из-за достаточно тривиальной задачи по форматированию даты ты еще вдогонку хочешь писать код по мутированию данных, чтобы везде были «хорошие» объекты

Какие «хорошие»? Какие объекты? И кто сказал, что мне нужно только форматирование? Плюс к тому надо проверять наступление новых дней, месяцев и прочего, запускать регулярные события. Но я тебе этого не писал, а то ты сейчас опять начнёшь плеваться бензином, что тебе не изложили весь замысел программы.

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от al_exquemelin

Плюс к тому надо проверять наступление новых дней, месяцев и прочего, запускать регулярные события.

Шедулер тоже внешний должен быть, так как не сцеплен с объектом никак, плюс готовых вагон и маленькая тележка, это точно не епархия бедного MyDate) SRP же, ну!

anonymous
()
Ответ на: комментарий от al_exquemelin

Какие «хорошие»? Какие объекты?

Твой MyDate же. Ты уперся в известную проблему с ООП. Для того чтобы везде был объектный интерфейс, надо все обмазывать обертками и адаптерами. Вместо того чтобы изменения сделать на внешней границе, ты аккуратно (или не очень) собираешься размазать это недоразумение по всей глубине.

За сим все, мы уже начинаем заходить на второй круг, если всех этих аргументов недостаточно, то тут только работа в течение нескольких лет исправит (возможно, хе-хе).

anonymous
()
Ответ на: комментарий от anonymous

Ты уперся в известную проблему с ООП. Для того чтобы везде был объектный интерфейс, надо все обмазывать обертками и адаптерами.

Чего только на лоре не услышишь

goingUp ★★★★★
()
Ответ на: комментарий от anonymous

Странная логика. У Васи есть часы, допустим. Каждый раз, когда их показания увеличились на час, Вася проверяет, не наступила ли полночь. Если наступила, он ложится спать, но проверяет перед этим дату. Если наступает 20-е число месяца, Вася знает, что утром ему выдадут зарплату. Вот и здесь будет та же ерунда, только это главные часы в программе, условно говоря, будут толкать Васю в кровать и отправлять в банк команду на выдачу зарплаты. И что здесь не связано с временем?

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от al_exquemelin

И что здесь не связано с временем?

Оно связано со временем, но предметная область не обязательно должна быть только в одном god-классе. Ты туда еще воткни генерацию html-календарей с праздниками РФ. А чо, тоже связано с временем.

anonymous
()
Ответ на: комментарий от goingUp

Чего только на лоре не услышишь

return MyTime(newDateTime)

Для того чтобы везде был объектный интерфейс, надо все обмазывать обертками и адаптерами.

Это просто праздник какой-то, не тупи, ты же вроде соображал раньше.

anonymous
()
Ответ на: комментарий от anonymous

Никто и не говорил, что всё делается в одном классе. Из моего счётчика нужно только дёргать вызовы других методов и функций:

if self._date.hour == 0
    Vasya.goto_sleep()
    if self._date.day == 20
        bank.pay(Vasya)

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от al_exquemelin

Как-то это некрасиво, Васю никто не должен дёргать, он сам должен проверять время, чтобы знать когда ему спать.

vvn_black ★★★★★
()
Ответ на: комментарий от vvn_black

Хмм. В принципе, можно проверку self._date.hour == 0 утащить в Васин класс, но как он узнает, когда смотреть на часы? Понял, см. ниже.

al_exquemelin ★★★
() автор топика
Последнее исправление: al_exquemelin (всего исправлений: 1)
Ответ на: комментарий от al_exquemelin

Из моего счётчика нужно только дёргать вызовы других методов и функций

Следи за моими движениями:

class VasyaCal:
   def on_date(self, dt):
       if dt.hour == 0
           Vasya.goto_sleep()
           if dt.day == 20
               bank.pay(Vasya)

Из твоих постов ниоткуда не следует что _date принадлежит «счетчику». Пример выше полностью реализует услышанную хотелку, при этом не надо изобретать свой datetime. Просто решает тривиальную задачу, без завязывания потока данных на стейт.

Нет, это все бесполезно.

anonymous
()
Ответ на: комментарий от al_exquemelin

Если продолжить про Васю, то я бы его подписал на событие «пробило полночь». А шедулер пусть событие генерит.

Связь можно и через Васину Queue организовать, к примеру.

vvn_black ★★★★★
()
Ответ на: комментарий от anonymous

_date принадлежит «счетчику»

Чему же ему ещё принадлежать? Пользовательский ввод «толкает» счётчик, а дальше так:

у меня: пользователь --> счётчик --> вызовы другим объектам
у тебя: пользователь --> счётчику увеличить значение, объектам проверить время

По-моему, хрен редьки не слаще.

al_exquemelin ★★★
() автор топика

Что-то на меня нашло и схематично накидал на корутинах, как управлять Василием:

class SomeObject(object):
    def __init__(self):
        self._queue = asyncio.Queue()

    @property
    def queue(self):
        return self._queue

    async def process(self):
        while True:
            event = await self._queue.get()

            if event == 'sleep':
                self._sleep()

            if event == 'go_to_bank':
                self._go_to_bank()

            if event == 'killed':
                break

    def _sleep(self):

    def _go_to_bank(self):

    ...



class Scheduler(object):

    def register(self, queue):
        self._pool.append(queue)

    async def process(self):
        while True:

            if self._date.hour == 0:
                for q in self._pool:
                    await q.put('sleep')

            if (self._date.hour == 8) and (self._date.day == 20):
                for q in self._pool:
                    await q.put('go_to_bank')



loop = asyncio.get_event_loop()

vasyan = SomeObject()
sch = Scheduler()
sch.register(vasyan.queue)

tasks = [asyncio.ensure_future(vasyan.process()),
         asyncio.ensure_future(sch.process())]

loop.run_until_complete(asyncio.wait(tasks))

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 2)
Ответ на: комментарий от vvn_black

Ох ты же ничего себе. Мне ещё разбираться и разбираться в таком, если раньше не надоест. Спасибо.

Вот это:

async def process(self):
        while True:
            event = await self._queue.get()
будет выполняться в отдельном цикле, независимым процессом, я правильно понимаю?

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от al_exquemelin

Да, await self._queue.get() приостановит выполнение метода process, пока в очереди не появится очередной элемент. И это будет выполняться «независимо», при условии, что остальная логика приложения тоже асинхронная.

Кстати, раз уж прозвучали выше слова про иммутабельность, есть ещё редуксоподобный вариант с единым state, его изменяющим «потоком» редьюсеров, экшенами и где-то только совсем сбоку вьюхой, которая будет выводить «полночь» вместо «0:00». Но это уже называется JavaScript ))

vvn_black ★★★★★
()

1)создать свой класс вроде class MyTime(datetime.datetime); 2)написать в нём метод, чтобы выводил текущее значение в нужном мне виде; 3)написать в нём метод, чтобы увеличивал текущее значение на заданную datetime.timedelta в зависимости от аргумента.

Ты всё делаешь не так. MyTime не нужен вообще. Нужны DateTimeFormatter и DateTimeIncrementer.

no-such-file ★★★★★
()
Ответ на: комментарий от vvn_black

Спасибо, так понятнее.

no-such-file

Нужны DateTimeFormatter и DateTimeIncrementer.

А регулярные события я откуда тогда буду пинать? А вообще, я уже написал через класс-обёртку, как сразу посоветовали. Работает.

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от al_exquemelin

А регулярные события я откуда тогда буду пинать?

Если ты про это

Плюс к тому надо проверять наступление новых дней, месяцев и прочего, запускать регулярные события

То ведь можно догадаться в контексте моего совета, что этим должен заниматься отдельный DateTimeChecker?

А вообще, я уже написал через класс-обёртку, как сразу посоветовали. Работает.

Лапшекод с goto тоже работает. Обёртка это конечно здорово, но всё таки выкинь из неё методы и добавь объекты formatter/incrementer/checker а в них уже реализуй логику. Тогда можно будет, не запиливая новый класс на каждый чих, менять логику работы отдельных компонентов - просто при настройке/инициализации обёртки передавая соответствующие объекты-реализации. А по большому счёту и никакой обёртки не нужно. Если уж совсем по-простому, то можно даже послушать чувака который советовал всё запилить по-пролетарски, обычными функциями, без классов.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 2)
Ответ на: комментарий от no-such-file

объекты formatter/incrementer/checker

Так а что это будут за объекты? Атрибуты? Функции?

можно даже послушать чувака который советовал всё запилить по-пролетарски, обычными функциями, без классов

Не, спасибо. Я из-за этого и завёлся, чтобы не складывать функции в корень модуля.

al_exquemelin ★★★
() автор топика
Ответ на: комментарий от al_exquemelin

Атрибуты? Функции?

Один атрибут - ссылка на объект datetime, одна функция format/inc/check. Если тебе лениво руками иницилизировать каждый объект объектом datetime, можешь запилить обёртку-фабрику, которая будет инициализироваться объектом datetime и возвращать по запросу соответствующий formatter и т.д.

чтобы не складывать функции в корень модуля

А кто тебя заставляет их складывать в корень модуля? Получай функции из фабрики.

dt_format = DTFabric.getFormatter()
dt_format(dtObj)

Или даже так

dt_format = DTFabric.getFormatter(dtObj)
dt_format()

no-such-file ★★★★★
()
Ответ на: комментарий от al_exquemelin

много лишней возни из-за единственного экземпляра, как по мне

В варианте с простыми функциями работы ровно столько же. Один класс фабрика и три функции в нем.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Окей, поверю на слово. Никогда не работал с фабриками и прочим таким.

al_exquemelin ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.