1 - Как можно предоставить метаклассы с информацией о конфигурации?
Есть несколько способов сделать это - так как ваши метаклассы живут в своем собственном модуле
(и да, модуль выполняется один раз в import
раз, независимо от того, сколько раз он был импортирован в одно и то же приложение), хороший способ настроить их - иметь вызываемый объект (либо класс или функция в том же модуле), который будет устанавливать «глобальные переменные», которые будут использоваться для конфигурации.
Несмотря на свою плохую репутацию из-за C, откуда происходит название «global», глобальные переменные в Python на самом деле являются «модульными» переменными: это означает, что все функции (включая методы) в этом модуле могут обращаться к этим переменным. Функции или код в других модулях должны иметь префикс имени модуля для этого.
Так что функция как:
def configure_servers(p1, p2,...):
global opt1, opt2, ...
opt1 = p1
opt2 = p2
(...)
Может быть вызвано из точки входа вашего приложения до создания экземпляров сервера. (Конечно, вы можете передать путь к файлу конфигурации вместо p1
, p2
, ...)
2 - Какой хороший способ передать экземпляр конфигурации SINGLE
через поток программы, чтобы быть
отредактировано, обновлено и возможно в конце концов
написано?
Имя глобальной переменной (модуля) в модуле метакласса может быть прочитано всеми ими, и оно может быть связано со сложным объектом конфигурации. Возможно, наличие функции «config», подобной приведенной выше, может сделать этот вопрос устаревшим.
Но если вам действительно нужен «одноэлементный» объект, то есть объект, у которого есть только один экземпляр, вы можете сделать это простым способом: иметь один класс в словаре метаклассов и передавать этот класс вокруг , а не экземпляр этого. Лучше и чище, если у вас есть словарь вместо класса.
Если вам нужно создать «настоящий» одноэлементный объект, вам следует создать класс и переопределить в нем метод __new__
, чтобы он всегда возвращал первый созданный экземпляр -
Пример: * +1028 *
class Singleton(object):
_instance = None
def __new__(cls, *args, **kw):
if cls._instance is not None:
return cls._instance
self = object.__new__(cls, *args, **kw)
cls._instance = self
return self
3 - Можно ли каким-то образом расширить входные аргументы метакласса за пределы
Metaclass.new (мета, имя, базы, атрибуты)?
Не использует синтаксис языка.
Я имею в виду, что всегда можно вызвать метакласс как обычный вызов Python, но это помешает вам использовать синтаксис языка для описания вашего класса: вам нужно определить тело класса как словарь для передачи как attrs
за звонок.
Например, чтобы создать производный класс исключений, можно сделать:
MyException = type("MyException", (Exception, ), {})
Вместо:
class MyException(Exception):
pass
Обычный способ передачи дополнительной информации в метакласс - использование атрибутов с фиксированными именами в теле класса. Затем метакласс проверяет эти атрибуты внутри attrs
и использует их. Затем он может выбрать сохранение в результирующем классе или удалить их из attrs
на данном этапе.
Если информация, необходимая для передачи метакласса, известна только во время выполнения, эти атрибуты могут указывать на другие (на уровне модуля) переменные или содержать выражения Python, которые оцениваются во время создания класса.
mod_server_type = "TCP"
class YAServer(ParentServer):
__metaclass__ = ServerMetaBase
_sever_type = mod_server_type
with open("config_file") as config:
_server_params = pickle.load(config)
del config
def __init__(self,...):
...
В приведенном выше примере ваш метакласс может использовать атрибуты _server_type
и _server_params
для дальнейшего управления созданием класса.