Когда я начал рефакторинг EFB Telegram Master Channel (ETM) для обновлений 2.0, я исследую способы организовать код в разные файлы достойным образом. В этой статье я хотел бы поговорить о стратегии, которую я использовал, по сравнению с другой кодовой базой, я читал тогда, ИТЧАТ
Отказ
В EUTM версии 1 большая часть кода написана тяжелая и уродливая 1675-линейная __init__.py
Отказ Поскольку в EUTM планируется добавить больше объектов, для меня было очень сложно ориентироваться по коду, что подняло мою потребность в рефакторинге этой огромной вещи.
Тогда (который, удивительно, был более 2 лет назад ) Основная ссылка у меня была достаточно большого проекта, было ИТЧАТ
. С тех пор их кодовая структура не меняется с тех пор. ИТЧАТ
У них было достаточно большой репозиторий кода, но так, как он разбивает его функции, довольно Unideal.
Путь ITCHAT сделал все функционировать определенным на корневом уровне каждого файла и иметь функцию погрузчика, которая «загружает» эти методы для объекта, называемого Core
который содержит некоторые данные конфигурации. В переводчик Python этот метод действительно работает благодаря своей динамической печати. Но это выглядит очень плохо, когда вы пытались работать с кодом, поскольку IDE обычно не может дать никакого намека с объектами, определенными таким образом. Это также происходит, когда вы пытаетесь работать над самой библиотекой, несмотря на все функцию начинается с Я
в их аргументах.
Затем я продолжал искать другие распространенные практики на разрушении большого класса, некоторые предложили импортирующие функции внутри функции, другой используют несколько наследований. [ Реф. ] Первый не сильно отличается от того, что ИТЧАТ
Делал, а последний выглядел многообещающим в начале. Я продолжал сделать некоторый эксперимент с несколькими наследованием, и обнаружил, что он обеспечивает лучшую автозаполнение с IDE, но только в основном классе. Я не вижу один подкласс от другого в IDE. Это все еще разумно, так как все эти подклассы объединяются только в основном классе, они не знают друг о друге.
# core.py from .components import load_components class Core: def method_1(self, param_1, param_2, param_3): """Doc string goes here.""" raise NotImplementedError() def method_2(self): """Doc string goes here.""" raise NotImplementedError() def method_3(self, param_1): """Doc string goes here.""" raise NotImplementedError() load_components(Core)
# components/__init__.py from .component_1 import load_component_1 from .component_2 import load_component_2 def load_components(core): load_component_1(core) load_component_2(core)
# components/component_1.py def load_contact(core): core.method_1 = method_1 core.method_2 = method_2 def method_1(self, param_1, param_2, param_3): # Actual implementation ... def method_2(self): # Actual implementation ...
# components/component_2.py def load_contact(core): core.method_3 = method_3 def method_3(self, param_1): # Actual implementation ...
Я думал себе, почему я не могу просто сделать еще несколько классов и позволить им ссылаться друг с другом? Оказывается, что работал довольно хорошо для меня. Я разделил свои функции на несколько различных классов «менеджера», каждый из которых инициализируется со ссылкой на основной класс. Эти классы создаются в топологическом порядке, так что классы, упомянутые другими, созданы ранее. В EUTM классы, которые упоминаются, обычно относятся к этим утилитам поставщиков данных, а именно ЭКСПЕРИМЕНТАЛЬНЫЙФОРМАГСМАНАГЕР
С DatabaseMaserager
и TelegrambotManager
.
# __init__.py from .flags import ExperimentalFlagsManager from .db import DatabaseManager from .chat_binding import ChatBindingManager class TelegramChannel(): def __init__(self): self.flags: ExperimentalFlagsManager = ExperimentalFlagsManager(self) self.db: DatabaseManager = DatabaseManager(self) self.chat_binding: ChatBindingManager = ChatBindingManager(self)
# flags.py from typing import TYPE_CHECKING if TYPE_CHECKING: # Avoid cycle import for type checking from . import TelegramChannel class ExperimentalFlagsManager: def __init__(channel: 'TelegramChannel'): self.channel = channel ...
# db.py from typing import TYPE_CHECKING from .flags import ExperimentalFlagsManager if TYPE_CHECKING: # Avoid cycle import for type checking from . import TelegramChannel class DatabaseManager: def __init__(channel: 'TelegramChannel'): self.channel: 'TelegramChannel' = channel self.flags: ExperimentalFlagsManager = channel.flags ...
# chat_binding.py from typing import TYPE_CHECKING from .chat_binding import ChatBindingManager from .db import DatabaseManager if TYPE_CHECKING: # Avoid cycle import for type checking from . import TelegramChannel class ChatBindingManager: def __init__(channel: 'TelegramChannel'): self.channel: 'TelegramChannel' = channel self.flags: ExperimentalFlagsManager = channel.flags self.db: DatabaseManager = channel.db ...
Во время рефакторинга ETM я узнал, что множественное наследование в Python также используется другим способом – смешины. Микс – это классы, которые полезны, когда вы хотите добавить набор функций во многих других классах. Это просветил меня, когда я пытался справиться с постоянно добавлять ссылки на GetText
Переводчик во всех классах менеджера.
Я добавил смешин под названием Localemixin
что извлекает функции переводчика ( getText
и netthtext
) Из основного класса ссылки (при условии, что они гарантированно будут там) и назначают локальное свойство, которое отражает эти методы.
class LocaleMixin: channel: 'TelegramChannel' @property def _(self): return self.channel.gettext @property def ngettext(self): return self.channel.ngettext
Когда классы Mixin добавляются в список унаследованных классов, IDE может правильно распознавать эти свойства вспомогательных свойств, а их определения консолидированы в одном месте. Я считаю, что это более организовано, что предыдущий стиль.
В конце концов, я обнаруживаю, что просто создание классов для каждого компонента моего кода оказывается наиболее организованным, и IDe-Fire способ для разрушения большого класса, а смешины полезны для создания ссылок или функции помощника для нескольких классов.
Пост Разделение большого класса и многократное наследование в Python появился первым на 1А23. Блог Отказ
Оригинал: “https://dev.to/blueset/splitting-a-large-class-and-multiple-inheritance-in-python-3n36”