Печать всех экземпляров класса

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

Это сбивающий с толку вопрос. Вам нужна функция метода, которая форматирует их все одинаково? Или вам нужна коллекция, содержащая все экземпляры?

S.Lott 30.11.2008 16:59

Попытка сделать что-то со всеми экземплярами класса почти всегда является ошибкой и признаком того, что вы еще не привыкли организовывать свои объекты с помощью структур данных. При правильных структурах данных правильная операция - это что-то вроде «делать [что-то] со всеми элементами этой структуры данных», а не «делать [что-то] со всеми экземплярами этого класса».

user2357112 supports Monica 03.06.2019 08:06
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
66
2
68 005
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

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

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

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

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

akuhn 30.11.2008 17:13

@ Адриан Кун: см. Сообщение @ NXC о возможностях Smalltalk allInstances. Может, Руби - последний противник?

S.Lott 30.11.2008 17:22

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

Matthew Trevor 01.12.2008 10:10
Ответ принят как подходящий

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

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

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

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

Используйте миксин и weakrefs

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.

+1 за примеры кода и демо для слабых ссылок. Сборщик мусора интересен, но, вероятно, не так полезен для этого типа приложений.

ConcernedOfTunbridgeWells 30.11.2008 18:47

Я знаю, но это последнее средство, если все остальное выйдет из строя. Может, стоило поставить как вариант 2.

Torsten Marek 01.12.2008 12:02

IMO OP спрашивает о методе __str __ ().

jfs 02.12.2008 01:11

Как бы вы расширили это, чтобы включить экземпляры дочерних классов?

juil 13.05.2016 22:08

Начиная с Python 2.7 это можно сделать немного проще, используя WeakSet.

Georg Schölly 19.02.2017 02:26

Если у меня есть два класса, которые наследуются от KeepRefs, то кажется, что _refs является общим для этих двух классов. Это не то, что я хотел, и я не понимал, что наследование классов будет работать таким образом. Означает ли это, что необходимо реализовать KeepRefs как метакласс, чтобы каждый класс, который его использует, получил свой собственный _refs?

Craig McQueen 22.09.2017 05:15

Очень красивый и полезный код, но у него есть большая проблема: список всегда больше и никогда не очищается, чтобы протестировать его, просто добавьте print(len(cls.__refs__[cls])) в конец метода get_instances. `@classmethod def get_instances (cls): cls .__ refs __ [cls] = [instance_ref for instance_ref in cls .__ refs __ [cls] \ if instance_ref () is not None] for instance_ref in cls .__ refs __ [cls]: instance = instance_ref ( ) yield instance print (len (cls .__ refs __ [cls])) `

Fabio Caccamo 27.04.2018 16:52

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

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

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

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

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

Вы захотите создать статический список в своем классе и добавить 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)

Можно ли распечатать все экземпляры класса без weakref или любого другого специального модуля? Что произойдет, если он будет написан как «self.name = name \ n self .__ class __. Instance.append (name) \ n»?

Joonho Park 01.06.2020 06:49

Очень красивый и полезный код, но у него есть большая проблема: список всегда больше, и он никогда не очищается, чтобы протестировать его, просто добавьте 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]

Вам не нужно НИЧЕГО импортировать! Просто используйте «я». Вот как ты это делаешь

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

    @classmethod
    def printInstances(cls):
        for instance in cls.instances:
            print(instance)
A.printInstances()

Все очень просто. Модули или библиотеки не импортированы

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

Avision 10.05.2020 14:43

В моем проекте я столкнулся с аналогичной проблемой и нашел простое решение, которое также может сработать для вас при перечислении и печати экземпляров вашего класса. Решение работало без сбоев в Python версии 3.7; дал частичные ошибки в Python версии 3.5.

Я скопирую и вставлю соответствующие блоки кода из моего недавнего проекта.

```
instances = [] 

class WorkCalendar:
    def __init__(self, day, patient, worker):
        self.day = day
        self.patient = patient
        self.worker= worker
    def __str__(self):
        return f'{self.day} : {self.patient} : {self.worker}'

В Python метод __str__, в конце концов, определяет, как объект будет интерпретироваться в его строковой форме. Я добавил : между фигурными скобками, это полностью мое предпочтение для чтения типа "Pandas DataFrame". Если вы примените эту небольшую функцию __str__, вы не увидите некоторые машиночитаемые описания типов объектов, что не имеет смысла для человеческого глаза. После добавления этой функции __str__ вы можете добавлять свои объекты в список и распечатывать их по своему усмотрению.

appointment= WorkCalendar("01.10.2020", "Jane", "John")
instances.append(appointment)

Для печати ваш формат в __str__ будет работать по умолчанию. Но также можно вызывать все атрибуты по отдельности:

for instance in instances:
    print(instance)
    print(instance.worker)
    print(instance.patient)

Для подробного прочтения вы можете посмотреть источник: https://dbader.org/blog/python-repr-vs-str

Другие вопросы по теме