LINUX.ORG.RU

ООП в Python

 


0

1

Добрый день, ЛОР.
Учусь ООП (точнее, его подобию) в Питуне.

Сходу вопрос: как можно разбить класс на несколько файлов?
Очевидное наследование, однако голова кипит и пока не могу сообразить, как и куда его пихать.

Допустим, есть класс, в нём есть метод logger(), который формирует и возвращает лог-строку с полезной информацией:

class BotInstance:

    chat_id = None
    users = []
    bot_debug = False

    def logger(self, message = ''):
        info = "[Chat {0}] [{1} users]".format(self.chat_id, len(self.users))
        return info + message


Как правильнее всего вынести эту функцию в отдельный файл?

★★★★☆

Последнее исправление: annerleen (всего исправлений: 1)

Я правильно понимаю, что нужно создать, например, класс BotUtils:

class BotUtils:
    def logger(self,message=''):
        ...


затем наследовать его уже из главного класса BotInstance:

import bot_utils
class BotInstance(BotUtils):
    ...



Это правильное решение?
А то как-то не совсем логично выглядит

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

как можно разбить класс на несколько файлов?

А зачем?

Я знаю только, что это можно сделать через наследование, но надо не забывать о неймспейсах.

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

Ну, допустим, есть Telegram-бот, в классе которого:

- Вспомогательные методы для логов, загрузки/сохранения состояния
- Вспомогательные методы для отправки/форматирования/удаления сообщений
- Обработчики команд (хотелось бы реализовать их как плагины)
- Интерфейс конфигурирования

Разве не логично было бы разбить класс бота на тематические «составляющие»?

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

1000500 файликов по чуть 10 строк в каждом ?

ggrn ★★★★★
()

Учусь ООП (точнее, его подобию) в Питуне.

Нуууу, с таким подхожом научиться тяжело. Почему подобию? Чего из парадигмы ООП нет в Python?

Сходу вопрос: как можно разбить класс на несколько файлов?

С ходу ответ: не надо так!

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

Заработать-то заработает, меня интересует, насколько архитектурно правильное это решение.

Почему вообще BotUtils это класс (!), а инстанс бота его наследует (!!) ?


Логика подсказывает, что это бы вообще правильнее сделать статическими методами...

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

Просто вызывай нужный метод и всё.

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

Почему вообще BotUtils это класс (!), а инстанс бота его наследует (!!) ?

да кто его знает, не я же писал этого бота.

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

Можешь разнести это по разным классам, если тебя напрягают большие классы.

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

Ты начал об одном, спрашиваешь о другом.

Если об ООП, то наследование вместе с полиморфизмом это об иерархии объектов, от простого и общего к сложному и частному.

Пока непонятно, что тебя тревожит?

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 1)

Сходу вопрос: как можно разбить класс на несколько файлов?

немного вброшу. в С# уже есть такое: partial классы.

bvn13 ★★★★★
()

Как правильнее всего вынести эту функцию в отдельный файл?

В питоне не нужно выносить метод класса в отдельный файл.

Сходу вопрос: как можно разбить класс на несколько файлов? Очевидное наследование, однако голова кипит и пока не могу сообразить, как и куда его пихать.

Ты всё перевернул с ног на голову. Наследование нужно не для разбиения кода на отдельные файлы.

Crocodoom ★★★★★
()
Последнее исправление: Crocodoom (всего исправлений: 1)

Программирование ромбиком, abc, вот это всё. По теме, ты какую-то херню городишь.

азбить класс на несколько файлов

зачем?

возвращает лог-строку с полезной информацией

очень полезная информация. Если серьёзно, то модуль logging это то что тебе нужно для этого, скорее всего. И кстати зачем тебе там присваивание вообще?

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

И кстати зачем тебе там присваивание вообще?
, то модуль logging это то что тебе нужно для этого,

Это очень условный код для примера.
Там пропущена большая часть кода с проверками, это не важно.

Хотел, чтобы объяснили на примере этого.

- Есть класс BotInstance;
- Есть «чужеродная» (т.е. то, что не должен делать BotInstance) для класса функция, например logger(), но которая использует свойства объекта;

Вопрос: как *правильнее* всего это должно быть реализовано в ООП?

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

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

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

Это сильно упрощённый пример из кода.
На самом деле там

info = "[Conference {0}] [{1} users] ".format(self.chat_id, len(self.users) ) if self.chat_id else ''
logstr = "{0}{1}<{2}():> {3}{4}".format(timestamp, info, event_by, message, debug) 


Но разве это принципиально?
Вопрос о другом же

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

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

anonymous
()

logger()

Один из очень редких случаев, когда от множественного наследования в mixin-стиле не хочется калечить.

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

Вообще, я бы хотел, пожалуй, весь код бота выложить, чтоб оценили что и как, что изменить нужно для достижения т.н. «best practices»

Но на лоре пацаны засмеют

annerleen ★★★★☆
() автор топика

Как правильнее всего вынести эту функцию в отдельный файл?

Есть класс Бот Кошка. Кошка умеет жрать, срать и мявкать. Кошка НЕ умеет логировать, поэтому у неё НЕ должно быть методов log, logger или ещё какой-то такой ереси.

Если ты сделаешь отдельный класс с методом logger и унаследуешь Кошку от него, то у Кошки будет метод logger. Напоминаю для идиотов, у кошки не должно быть метода logger. Так делать нинужно.

Сделай отдельный класс Logger и передай его инстанцию боту. Так его всегда можно поменять на другой. А лучше используй готовый, он в питоне уже есть.

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

Вот, спасибо!
То, что хотел услышать!

Что с методами save_state(), load_state(), которые записывают состояние инстанса бота в файл?
Это тоже нужно уносить в отдельный класс?

И тот же вопрос про функции «помощники» для упрощения жизни.

К примеру, отправка сообщения через telegram lib:

bot.send_message(chat_id, message, reply_to_message_id, ...


которую я обернул в

def reply(self, message, event):
    # ...
    return self.bot.send_message...


Это метод «бот» тоже по-идее не должен уметь? Или всё же должен..
Не понимать!

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

Ах да, в телеграмной либе мы не можем унаследовать, например, класс бота/апдейтера, там всё на update events и handlers
Поэтому сделал как-то так, тоже не знаю, насколько это правильно

bot_instances = {}

def callBot(bot, update):
    
    # if we don't have instance for this chat AND this chat is not private -- create our bot instance.
    if not update.message.chat_id in bot_instances and update.message.chat.type != 'private': 
        bot_instances[update.message.chat_id] = OraculBot(bot, update)
    
    # if instance created successfully, we can call it passing an event:
    if update.message.chat_id in bot_instances and bot_instances[update.message.chat_id]: 
        bot_instances[update.message.chat_id](update)

dispatcher.add_handler(MessageHandler(Filters.text | Filters.status_update, callBot)) # handling any messages with function callBot()

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

Вот, спасибо!
То, что хотел услышать!

Не за что. Теперь самое главное, так как ты походу этого не знаешь. Всё это ООП-шмооп затеяно с одной целью — писать надёжный, читаемый, поддерживаемый код.

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

Иногда будет оказываться, что лучше бы было сделать по другому. Но заранее этого ты не знал, знал бы — соломки бы подстелил, ага. Иногда наоборот, будешь радоваться, как удачно обошёл проблему. Чаще всего разницы не будет.

Что с методами save_state(), load_state(), которые записывают состояние инстанса бота в файл?
Это тоже нужно уносить в отдельный класс?
И тот же вопрос про функции «помощники» для упрощения жизни.

Выноси.

Это метод «бот» тоже по-идее не должен уметь? Или всё же должен..
Не понимать!

А я тем более. Определись, умеет твой бот отвечать или не умеет.

anonymous
()

У меня прямо сейчас перед глазами класс который инстанцирует себе несколько разных объектов, хех. Ну задумка была типа каждый объект будет жить отдельно (и в отдельном процессе) и шарить пулы только между тредами, как максимум. Кстати вполне рабочий вариант, разве что пишешь вместо self.loginfo() self.logobj=otherfile.LogObj(); self.logobj.loginfo(). Почему-то мысли наследоваться от десятка классов не пришло. Наверно лучше builder pattern, но пока лень, там всего-то сорок воркеров будет максимум. И так работает. Главное верно оценивать перспективы и потенциальные затраты на сопровождение.

anonymous
()

точнее, его подобию

это ты так выпендриваешься ?

разбить класс на несколько файлов

это антипаттерн. Для подобных извращений есть множественное наследование, но то что ты хочешь делается функциями.

Очевидное наследование

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

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

это ты так выпендриваешься ?

У вас там приватные аттрибуты класса не приватные почему-то.
Хотя, может и я наркоман (скорее всего да)

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

приватные аттрибуты

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

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

у вас ООП не ООП
это ты так выпендриваешься ?
гдже инкапсуляция?
НИНУЖНА!

:)

Я ничего не имею против путона, нормальный скриптовый язычок:)

annerleen ★★★★☆
() автор топика

А почему груда кода в одном файле тебя смущает, а в одном классе - нет?

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

я именно для этого и создал тред

чтобы понять, что должно быть в классе, что нет, и как это реализовать лучше

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

гдже инкапсуляция?

эм, в конвенции тащем-то, нигде не указано что компилятор дожен тебе по рукам давать

путона

ух, да, зря я с тобой диалог завел.

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

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

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

Зачем триггериться-то?

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

для меня инкапсуляция — неотъемлимая часть ООП, которой тут не завезли

Хм... А что в вашем понимании такое «инкапсуляция»? В моём питоне она присуствует.

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

Не обращайте внимания, я наркоман, наверное.
Каким-то образом извне экземпляра класса удавалось перезаписать __private переменную. Теперь уже нет Оо

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

Так инкапсуляция же не про это. Инкапсуляция, это самое простое - объединение данных и кода в одну структуру, и всё.

Открытая или закрытая, это же уже больше чем определение, это уже реализация в конкретном случае. Можно быть недовольным реализацией, но говорить, что этого «не завезли» - не надо так.

vvn_black ★★★★★
()

разбить класс на несколько файлов?

В питоне разбить класс на несколько файлов невозможно. Такую возможность я видел только в C#, если память не изменяет. Не знаю, есть ли еще языки, умеющие такое.

Дальше вопрос не читал т.к. у тебя там какая-то малопонятная муть вместо вопроса.

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

Каким-то образом извне экземпляра класса удавалось перезаписать __private переменную.

Так это же by design, просто примите это, что в питоне так можно.

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

В питоне вообще можно как угодно классы конструировать на ле

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

Если ты сделаешь отдельный класс с методом logger и унаследуешь Кошку от него, то у Кошки будет метод logger.

Унаследовать кошку от логера? Мдя, суровое у вас ООП.

bread
()

ТС, попробуй может композицию вместо наследования. Логер сделай внешним объектом и передавай ему всю необходимую инфу через аргументы. Не советовал бы изгаляться с миксинами, которых в питоне нет. Их конечно можно накостылять через множественное наследование, но типичный питонщик это не оценит.

bread
()

Никогда так не делайте :)

# file: tg_logger.py
def log(self, message = ''):
    print("MSG:", message)
# file usage.py
import tg_logger

class Bot:
    log = tg_logger.log
rymis ★★
()
Последнее исправление: rymis (всего исправлений: 1)
Ответ на: комментарий от pawnhearts

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

Миксины — зло. Без исключений.

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