Печать всех экземпляров класса - PullRequest
53 голосов
/ 30 ноября 2008

Как определить класс в Python для функции, которая будет печатать каждый экземпляр класса в формате, определенном в функции?

Ответы [ 6 ]

85 голосов
/ 30 ноября 2008

Я вижу два варианта в этом случае:

Сборщик мусора

import gc
for obj in gc.get_objects():
    if isinstance(obj, some_class):
        dome_something(obj)

Недостатком является то, что он очень медленный, когда у вас много объектов, но работает с типами, над которыми у вас нет контроля.

Используйте миксин и слабые звуки

from collections import defaultdict
import weakref

class KeepRefs(object):
    __refs__ = defaultdict(list)
    def __init__(self):
        self.__refs__[self.__class__].append(weakref.ref(self))

    @classmethod
    def get_instances(cls):
        for inst_ref in cls.__refs__[cls]:
            inst = inst_ref()
            if inst is not None:
                yield inst

class X(KeepRefs):
    def __init__(self, name):
        super(X, self).__init__()
        self.name = name

x = X("x")
y = X("y")
for r in X.get_instances():
    print r.name
del y
for r in X.get_instances():
    print r.name

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

Другая проблема в этом случае заключается в том, что вы должны обязательно вызвать конструктор базового класса. Вы также можете переопределить __new__, но только метод __new__ первого базового класса используется при создании экземпляра. Это также работает только для типов, находящихся под вашим контролем.

Редактировать : метод печати всех экземпляров в соответствии с определенным форматом оставлен в качестве упражнения, но в основном это всего лишь разновидность for -loops.

22 голосов
/ 27 февраля 2012

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

import weakref

class A:
    instances = []
    def __init__(self, name=None):
        self.__class__.instances.append(weakref.proxy(self))
        self.name = name

a1 = A('a1')
a2 = A('a2')
a3 = A('a3')
a4 = A('a4')

for instance in A.instances:
    print(instance.name)
5 голосов
/ 27 апреля 2018

Очень хороший и полезный код, но у него есть большая проблема: список всегда больше , и он никогда не очищается, для проверки просто добавьте print(len(cls.__refs__[cls])) в конце get_instances способ.

Здесь исправление для метода get_instances:

__refs__ = defaultdict(list)

@classmethod
def get_instances(cls):
    refs = []
    for ref in cls.__refs__[cls]:
        instance = ref()
        if instance is not None:
            refs.append(ref)
            yield instance
    # print(len(refs))
    cls.__refs__[cls] = refs

или, альтернативно, это можно сделать с помощью WeakSet:

from weakref import WeakSet

__refs__ = defaultdict(WeakSet)

@classmethod
def get_instances(cls):
    return cls.__refs__[cls]
3 голосов
/ 30 ноября 2008

Python не имеет эквивалента #allInstances для Smallktalk, так как в архитектуре нет централизованной таблицы объектов этого типа (хотя современные smalltalks тоже на самом деле не работают).

Как говорит другой автор, вы должны явно управлять коллекцией. Его предложение фабричного метода, который поддерживает реестр, является вполне разумным способом сделать это. Возможно, вы захотите что-то сделать с слабыми ссылками , поэтому вам не нужно явно отслеживать удаление объекта.

3 голосов
/ 30 ноября 2008

То же, что и почти все другие языки ОО, храните все экземпляры класса в некоторой коллекции.

Вы можете попробовать такие вещи.

class MyClassFactory( object ):
    theWholeList= []
    def __call__( self, *args, **kw ):
         x= MyClass( *args, **kw )
         self.theWholeList.append( x )
         return x

Теперь вы можете сделать это.

object= MyClassFactory( args, ... )
print MyClassFactory.theWholeList
1 голос
/ 30 ноября 2008

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

В любом случае я бы решил эту проблему, написав фабрику классов с использованием поддержки метаклассов Python. Если у вас нет контроля над классом, вручную обновите __metaclass__ для класса или модуля, который вы отслеживаете.

См. http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html для получения дополнительной информации.

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