Всегда ли плохо собирать все экземпляры в переменной класса?

Рассмотрим две версии простой модели погоды, в которой хранится местоположение облаков:

class cloud:
    def __init__(self, x, y):
        self.x = x
        self.y = y

collection = []
collection.append(cloud(1,2))
collection.append(cloud(4,6))

def update_all_clouds(collection):
    for c in collection:
        cloud.x += 1
        cloud.y += 1

update_all_clouds(collection)

vs

class cloud:
    collection = []
    def __init__(self, x, y)
        self.x = x
        self.y = y
        cloud.collection.append(self)
    @classmethod
    def update_all(cls):
        for c in cloud.collection:
            c.x += 1
            c.y += 1
cloud(1,2)
cloud(4,6)
cloud.update_all()

В основном это было наказано здесь ">Плохо ли хранить все экземпляры класса в поле класса? но здесь делается упор на методы класса, которые действуют на все экземпляры. Нечего ли сказать о простоте последних трех строк, которую дает второй подход?

Я знаю, что другим подходом было бы создание класса, подобного списку, называемого, например, collection и предоставления этому классу методов, таких как update_all(), но мне это не кажется намного лучше.


person hlud6646    schedule 09.07.2015    source источник


Ответы (3)


Вообще это плохо, да, по той простой причине, что объекты, находящиеся в списке, сохраняют ссылку на них практически навсегда. Наличие ссылки на объект предотвращает его сборку мусора. Таким образом, объекты вашего типа по существу живут вечно (пока программа не завершится), и память, которую они занимают, никогда не будет освобождена.

Конечно, если у вас есть очень специфическая потребность в этом и вы полностью контролируете время создания объектов, вы можете сделать это таким образом. Но в целом явное лучше, чем неявное, поэтому лучше иметь настоящая коллекция, в которую вы добавляете эти элементы. Эта коллекция может даже жить в типе, поэтому вы можете сделать:

obj = Cloud(…)
Cloud.add(obj)

# or even
obj = Cloud(…).persistInType()

Вы также можете использовать слабые ссылки, чтобы избежать описанной выше проблемы, но это дополнительные накладные расходы. , и немного сложнее в управлении. Так что просто сделайте себе одолжение и соберите объекты вручную.

person poke    schedule 09.07.2015
comment
будет иметь необязательный аргумент add_to_collection=False в init, чтобы добавление объекта в коллекцию проверялось по этой переменной, что делает вещи явными? - person k4vin; 09.07.2015
comment
Думаю, это могло бы сработать. Но вы также должны добавить некоторую функциональность, чтобы иметь возможность удалять объект, удаляя его из списка. - person poke; 09.07.2015
comment
Код, который я разместил, является упрощением. Коллекция постоянно выбраковывается @poke - person hlud6646; 09.07.2015

Учитывая, что явное лучше, чем неявное (см. Дзен Python), возможно, лучше всего иметь два класса: Cloud и CloudCollection. Это позволит вам написать такой код:

collection = CloudCollection()
collection.add(Cloud(1, 2))
collection.add(Cloud(4, 6))
collection.shift(1, 1)
person dlask    schedule 09.07.2015
comment
В соответствии с «Простое лучше, чем сложное» и «Особые случаи не настолько особенные, чтобы нарушать правила», вы бы просто использовали там обычный список ;) - person poke; 09.07.2015
comment
Как только мы сможем увидеть коллекцию как автономную сущность со своими собственными манипуляторами, на мой взгляд, уместно использовать для нее выделенный класс. Я не говорю, что это обязательно случай ОП. - person dlask; 09.07.2015
comment
закончилось сбором классов (список) и облаками = collection () и т. д. - person hlud6646; 09.07.2015

Этот вопрос можно просто свести к вопросу об использовании глобальных переменных, поскольку изменяемый член уровня класса — это просто глобальная переменная в другом пространстве имен.

Все аргументы против использования глобальных переменных применимы и к этому.

person shx2    schedule 09.07.2015
comment
Это на самом деле хуже, чем просто глобальная переменная. Это была бы «просто» глобальная переменная, если бы вызывали Cloud.addObject(cloudObj), но здесь объекты добавляются автоматически. - person poke; 09.07.2015