2015-06-11 2 views
2

Скажем, у меня есть класс под названием A, и я хочу перечислить все объекты, созданные из этого конкретного класса. Это то, что я сделал до сих пор, и он поднимает AttributeError: type object 'A' has no attribute 'items' Как это сделать?Автоматически добавлять вновь созданные объекты в список

class A: 
    def __init__(self): 
     self.items = [] 
     self.items.append(self) 

    @classmethod 
    def list_objects(cls): 
     return cls.items 


a = A() 
b = A() 
print(A.list_objects()) 

# Expected output is [a,b] 
+3

'self.items 'является атрибутом экземпляра. Переместите его в тело класса. –

+1

Обратите внимание, что сохранение экземпляров в списке таким образом приведет к сбою мусора, т. Е. Они не собираются собирать мусор, если вы не удалите их из списка вручную. Рассмотрите возможность использования [WeakSet] (https://docs.python.org/2/library/weakref.html#weakref.WeakSet), если заказ не является проблемой. –

+0

Ответ на этот вопрос, поэтому я просто хочу добавить, что это обычно не очень хорошая идея, потому что он вводит глобальное состояние, что делает повторное использование и тестирование труднее. – BlackJack

ответ

6

Вы должны были бы список, чтобы быть на уровне класса, а не на уровне экземпляра

class A: 
    items = [] 

    def __init__(self): 
     A.items.append(self) 

    @classmethod 
    def list_objects(cls): 
     return cls.items 

Тогда вы увидите

>>> a = A() 
>>> b = A() 
>>> A.list_objects() 
[<__main__.A object at 0x02B77230>, <__main__.A object at 0x02B772D0>] 
+0

Только что понял это сейчас, но не отвечаю сейчас. –

1

Проблема с кодом находится в self.items = [] части , поскольку вы инициализируете новый пустой список items для каждого экземпляра класса A, который вы создаете. Поэтому в вашем случае каждый объект класса A будет иметь экземпляр items, содержащий только себя.

Так что в первую очередь вам нужно переместить свой items список на уровень класса, а затем в __init__ добавить self в этот список.

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

@track_objects 
class A: 
    def __init__(self): 
     pass # your init code here 

>>> a = A() 
>>> b = A() 
>>> A.items 
[<__main__.A instance at 0x1004873f8>, <__main__.A instance at 0x100487488>] 

и это @track_objects реализация:

def track_objects(klass): 
    klass.items = [] 
    orig_init = klass.__init__ 

    def init_wrapper(self, *args, **kwargs): 
     self.items.append(self) 

     return orig_init(self, *args, **kwargs) 
    klass.__init__ = init_wrapper 

    return klass 
Смежные вопросы