Как разделить общий контекст между классами?
Настоящий сценарий:
У меня есть набор классов, которые все принимают общий аргумент context
в конструкторе, и все классы наследуются от общей базы.
class base:
def common_method(self):
pass
class a(base):
def __init__(self,context, aa):
pass
class b(base):
def __init__(self, context, bb):
pass
# ...
class z(base):
def __init__(self, context, zz):
pass
Использование в основном:
context = get_context_from_some_method()
A = a(context, 1)
B = b(context, 2)
C = c(context, 3)
D = d(context, 4)
.
.
.
Z = z(context, 26)
Проблема:
- Есть ли сложный способ доставки
context
всем классам неявно? - У нас есть общий базовый класс, но я не вижу очевидного способа позволить ему устанавливать контекст для всех классов.
- Можно предположить, что я хочу сохранить общий контекст для всех моих экземпляров классов.
- Просто случайная мысль - Может ли метакласс помочь?
Я знаю, что это кажется глупым, но я просто хочу каким-то образом избавиться от избыточности, чтобы я мог как-то установить глобальный контекст и сконцентрироваться на своих объектах.
Пожалуйста, предложите какой-нибудь способ?
** Обновление на вопрос **
Я не могу установить контекст в базовом классе, так как он должен использоваться в веб-приложении. Таким образом, многие страницы с различным контекстом будут использовать структуру класса. Итак, если я установлю контекст в базе, то он будет конфликтовать с контекстом, который будет установлен другим экземпляром веб-страницы, которая будет использовать ту же базу. Так как в веб-приложении все вышеперечисленные классы будут в памяти общими для всех страниц.
4 ответа
Изменить: Если вы не хотите / не можете использовать переменную класса, лучше всего использовать фабричную функцию. Либо сделайте его статическим методом в базовом классе, либо функцией уровня модуля.
def make_instances(context, *instances):
return [cls(context, *args) for cls, args in instances]
A, B, ..., Z = make_instances(get_context_from_some_method(),
(a, (1,)), (b, (2,)), ..., (z, (26,)))
# or
instances = make_instances(get_context_from_some_method(),
zip(list_of_subclasses, ((x,) for x in range(1, 27))))
В качестве альтернативы, и я не знаю, работает ли это в вашей ситуации, просто используйте глобальную переменную уровня модуля:
class z(base):
def __init__(self, zz):
self.zz = zz
self.context = context
context = 'abc'
Z = z(26)
В дополнение к совету использовать переменные класса из другого ответа, я советую вам скопировать контекст на экземпляры, чтобы впоследствии вы могли изменить контекст, не затрагивая уже созданные экземпляры.
class base:
context = None # if you want to be able to create without context.
# just omit the previous line if you want an error
# when you haven't set a context and you try to instantiate a subclass
class a(base):
def __init__(self, aa):
self.aa = aa
self.context = self.context # sets an instance variable
# so the class variable can be changed
class b(base):
def __init__(self, bb):
self.bb = bb
self.context = self.context
base.context = 'context'
A = a(1)
B = b(2)
base.context = 'newcontext'
print A.context # context
Вы можете использовать переменные класса:
base.context = 'context'
A = a(1)
B = b(2)
#...
Способ устранения избыточности состоит в том, чтобы идентифицировать повторяющиеся шаблоны и выделить шаблон в отдельный фрагмент кода.
Не уверен, что это ваш настоящий код, но из вашего примера вы видите, что вы создаете целую кучу классов аналогичным образом. Даже если вы удалили 9 символов из каждой строки, необходимо ввести context,
Вы все еще делаете:
A = a(1)
B = b(2)
C = c(3)
...
Что бы свести меня с ума. Проблема с избыточностью заключается не столько в типизации, сколько в том, что если вы хотите изменить это (скажем, хотите начать с 0, или вы хотите добавить дополнительный аргумент для каждого класса или что-то еще), вы должны изменить каждую строку,
Поэтому я бы предпочел сделать что-то вроде этого:
classes = [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]
instances = [cls(context, i) for i, cls in enumerate(classes, 1)]
Здесь у меня есть код, который ясно говорит, что я создаю экземпляр целой группы классов, и что я передаю контекст каждому, а также целое число от 1 до количества классов, которые у меня есть (увеличивается для каждого класса). И легко самостоятельно решить, что такое список классов или что я передаю каждому классу.
Это означает, что мои экземпляры имеют такие имена, как instances[0]
а также instances[13]
вместо A
а также N
, Есть также способы обойти это, но я нахожу редким создание экземпляра коллекции вещей, а затем использование их как независимых отдельных вещей, а не как коллекции.
Вы должны определить контекст как атрибут класса base. Изменение вашего примера будет:
class base:
context = None
def common_method(self):
pass
class A(base):
def __init__(self, aa):
pass
class B(base):
def __init__(self, bb):
pass
.
.
.
class Z(base):
def __init__(self, zz):
pass
base.context = get_context_from_some_method()
A = a(1)
B = b(2)
Z = z(3)
Все экземпляры A, B и Z имеют одно и то же свойство контекста.