打印类的所有实例

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

97898 次浏览

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

你可以试试这个。

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

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

收垃圾的

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

在这种情况下,所有引用都作为弱引用存储在列表中。如果您频繁地创建和删除大量实例,那么您应该在迭代之后清除弱点列表,否则将会出现大量的 cruft。

这种情况下的另一个问题是,您必须确保调用基类构造函数。也可以重写 __new__,但是在实例化时只使用第一个基类的 __new__方法。这也只适用于您控制的类型。

Edit : 根据特定格式打印所有实例的方法留作练习,但它基本上只是 for循环的变体。

Python 没有相当于 Smalltalk 的 # allInstances,因为体系结构没有这种类型的中心对象表(尽管现代的 Smalltalk 也不是这样工作的)。

正如另一张海报所说,你必须明确地管理一个集合。他建议使用工厂方法来维护注册表,这是一种完全合理的方法。您可能希望使用 参考文献不足执行一些操作,这样就不必显式地跟踪对象处理。

目前还不清楚是否需要一次打印所有类实例,还是需要在初始化时打印所有类实例,也不清楚是否需要在第三方库中打印一个可以控制的类。

在任何情况下,我都会使用 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)

非常漂亮和有用的代码,但它有一个大问题: 名单总是很长和它从来没有清理,只是在 get_instances方法的结尾添加 print(len(cls.__refs__[cls]))来测试它。

下面是 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]

您不需要导入任何东西! 只需使用“ self”

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

就这么简单,没有导入任何模块或库

在我的项目中,我遇到了类似的问题,并且找到了一个简单的解决方案,它可能也适用于列出和打印类实例。该解决方案在 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__方法决定如何以字符串形式解释对象。我在花括号之间添加了 :,它们完全是我喜欢的“熊猫数据框架”类型的阅读。如果你应用这个小的 __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