Pythonic способ инициализации (сложных) статических членов данных - PullRequest
17 голосов
/ 16 мая 2009

У меня есть класс со сложным элементом данных, который я хочу сохранить "статичным". Я хочу инициализировать его один раз, используя функцию. Как Pythonic что-то вроде этого:

def generate_data():
    ... do some analysis and return complex object e.g. list ...

class Coo:
    data_member = generate_data()
    ... rest of class code ...

Функция generate_data занимает много времени и возвращает данные, которые остаются постоянными в объеме работающей программы. Я не хочу, чтобы он запускался каждый раз, когда создается экземпляр класса Coo.

Кроме того, чтобы проверить, пока я ничего не назначаю data_member в __init__, он останется "статичным"? Что если метод в Coo добавляет некоторое значение к data_member (при условии, что это список) - будет ли это дополнение доступно для остальных экземпляров?

Спасибо

Ответы [ 3 ]

15 голосов
/ 16 мая 2009

Вы правы по всем пунктам. data_member будет создан один раз и будет доступен для всех экземпляров coo. Если какой-либо экземпляр изменяет его, это изменение будет видно для всех остальных экземпляров.

Вот пример, который демонстрирует все это, с выводом в конце:

def generate_data():
    print "Generating"
    return [1,2,3]

class coo:
    data_member = generate_data()
    def modify(self):
        self.data_member.append(4)

    def display(self):
        print self.data_member

x = coo()
y = coo()
y.modify()
x.display()

# Output:
# Generating
# [1, 2, 3, 4]
14 голосов
/ 16 мая 2009

Поскольку другие ответили, вы правы - я добавлю еще одну вещь, о которой следует знать: если экземпляр изменяет сам объект coo.data_member, например

self.data_member.append('foo')

тогда модификацию видят остальные экземпляры. Однако, если вы делаете

self.data_member = new_object

затем создается новый экземпляр члена, который переопределяет члена класса и виден только этому экземпляру, а не остальным. Разницу не всегда легко заметить, например self.data_member += 'foo' против self.data_member = self.data_member + 'foo'.

Чтобы избежать этого, вы, вероятно, всегда должны ссылаться на объект как coo.data_member (не через self).

6 голосов
/ 16 мая 2009

Оператор data_member = generate_data() будет выполнен только один раз, когда class coo: .... В большинстве случаев операторы класса происходят на уровне модуля и выполняются при импорте модуля. Таким образом, data_member = generate_data() будет выполнено только один раз при первом импорте модуля с классом coo.

Все экземпляры класса coo будут совместно использовать data_member и могут получить к нему доступ, написав coo.data_member. Любые изменения, внесенные в coo.data_member, будут немедленно видны любому экземпляру coo. Экземпляр может иметь свой собственный атрибут data_member. Этот атрибут можно установить, набрав self.data_member = ... и будет виден только этому экземпляру. Вы можете получить доступ к «статическому» data_member, набрав coo.data_member.

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