Каков наилучший способ реорганизации проекта и рефакторинга кода, чтобы он сохранил свою текущую возможность доступа ко всему остальному?
Я думаю, что вы на самом деле уже достаточно близки, и, вероятно, лучше, чем многие проекты Python, в которых они просто предполагают, что существует только один экземпляр приложения, и храните значения, специфичные для приложения, в модуле global или singleton.
(Это нормально для многих простых приложений, но на самом деле лучше всего иметь возможность объединить все в один объект Application, который владеет всеми внутренними классами и методами, которые должны знать состояние приложения.)
Первое, что я хотел бы сделать из внешнего вида приведенного выше кода, это выделить какие-либо из тех модулей и классов, которые не являются основной компетенцией вашего приложения, вещи, которые не обязательно должны иметь доступ к состоянию приложения. , Такие названия, как «Utils» и «Misc», звучат подозрительно, так как большая часть их содержимого на самом деле не относится к вашему приложению; возможно, они могут быть реорганизованы в отдельные автономные модули или подмодули вашего пакета, которые имеют только статические функции, вещи, не зависящие от состояния приложения.
Далее, я бы поместил класс Application основного владельца в пакет __init__.py, а не в «главный скрипт». Затем из вашего run-скрипта или просто интерпретатора вы можете получить полный экземпляр приложения просто:
import myapplication
a= myapplication.Application()
Можно также рассмотреть возможность перемещения любых базовых параметров развертывания из класса «Настройки» в инициализатор:
a= myapplication.Application(basedir= '/opt/myapp', site= 'www.example.com', debug= False)
(Если у вас есть только один возможный набор настроек и каждый раз, когда вы создаете экземпляр Application (), вы получаете один и тот же, мало смысла в том, чтобы использовать всю эту возможность для инкапсуляции всего приложения; вы могли бы просто использовать глобальные переменные модуля). .)
Что я делаю с некоторыми из моих приложений, так это превращаю собственные классы в обезьяну-патч, превращая их в настоящих членов объекта-владельца:
# myapplication/__init__.py
class Application(object):
def __init__(self, dbfactory, debug):
# ...
self.mailer= self.Mailer(self)
self.webservice= self.Webservice(self)
# ...
import myapplication.mailer, myapplication.webservice
# myapplication/mailer.py
import myapplication
class Mailer(object):
def __init__(self, owner):
self.owner= owner
def send(self, message, recipients):
# ...
myapplication.Application.Mailer= Mailer
Затем можно расширять, изменять или настраивать приложение извне, заменяя / подклассируя внутренние классы:
import myapplication
class MockApplication(myapplication.Application):
class Mailer(myapplication.Application.Mailer):
def send(self, message, recipients):
self.owner.log('Mail send called (not actually sent)')
return True
Меня не беспокоит целостность внутренних данных
Ну, нет, это Python, а не Java: мы не слишком беспокоимся о злых программистах, использующих свойства и методы, которые они не должны, мы просто помещаем '_' в начале имени, и пусть это будет подходящим предупреждением всем.
И эти длинные цепочки также замедляют код.
Не очень заметно. Читаемость является важным фактором; все остальное - преждевременная оптимизация.