打印类的所有实例

问题描述 投票:0回答:8

对于 Python 中的类,如何定义一个函数来以函数中定义的格式打印该类的每个实例?

python class
8个回答
127
投票

在这种情况下我看到两个选择:

垃圾收集器

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

这有一个缺点,当你有很多对象时,速度会非常慢,但适用于你无法控制的类型。

使用mixin和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

在这种情况下,所有引用都作为弱引用存储在列表中。如果您频繁创建和删除大量实例,则应该在迭代后清理weakrefs列表,否则会产生很多垃圾。

这种情况下的另一个问题是您必须确保调用基类构造函数。您也可以重写

__new__
,但在实例化时仅使用第一个基类的
__new__
方法。这也仅适用于您控制下的类型。

编辑:根据特定格式打印所有实例的方法留作练习,但它基本上只是

for
循环的变体。


33
投票

您需要在类上创建一个静态列表,并向每个实例添加

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)

33
投票

您不需要导入任何东西!就用“自己”吧。这是你如何做到这一点

class A:
    instances = []
    def __init__(self):
        A.instances.append(self) # suggested by @Herrivan
print('\n'.join(A.instances)) #this line was suggested by @anvelascos

就这么简单。没有导入模块或库


9
投票

非常好的和有用的代码,但它有一个大问题:列表总是更大并且它永远不会被清理,要测试它只需在

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]

7
投票

与几乎所有其他面向对象语言一样,将类的所有实例保存在某种集合中。

你可以尝试这样的事情。

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

4
投票

Python 没有与 Smallktalk 的 #allInstances 等效的东西,因为该体系结构没有这种类型的中心对象表(尽管现代的 Smalltalks 也不是这样工作的)。

正如另一位发帖者所说,您必须显式管理集合。他对维护注册表的工厂方法的建议是一种完全合理的方法。您可能希望使用弱引用做一些事情,这样您就不必显式跟踪对象处置。


2
投票

不清楚您是否需要立即打印所有类实例或在初始化它们时打印所有类实例,也不清楚您是否正在谈论您可以控制的类与第 3 方库中的类。

无论如何,我都会通过使用 Python 元类支持编写类工厂来解决这个问题。如果您无法控制该类,请手动更新您正在跟踪的类或模块的

__metaclass__

请参阅 http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html 了解更多信息。


1
投票

在我的项目中,我遇到了类似的问题,并找到了一个简单的解决方案,该解决方案也可能适合您列出和打印类实例。该解决方案在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

© www.soinside.com 2019 - 2024. All rights reserved.