Как разделить общий контекст между классами? - PullRequest
0 голосов
/ 22 марта 2012

Настоящий сценарий:

У меня есть набор классов, которые все принимают общий аргумент 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 ]

2 голосов
/ 22 марта 2012

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

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
1 голос
/ 22 марта 2012

Вы можете использовать переменные класса:

base.context = 'context'
A = a(1)
B = b(2)
#...
0 голосов
/ 22 марта 2012

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

Не уверен, что это ваш настоящий код, но из вашего примера вы видите, что вы создаете целую кучу классов аналогичным образом. Даже если вы удалили 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. Есть также способы обойти это, но я нахожу редким создание экземпляра коллекции вещей, а затем использование их как независимых отдельных вещей, а не как коллекции.

0 голосов
/ 22 марта 2012

Вы должны определить context как атрибут класса 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 имеют одно и то же свойство context .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...