简体   繁体   English

打印 class 的所有实例

[英]Printing all instances of a class

With a class in Python, how do I define a function to print every single instance of the class in a format defined in the function? With a class in Python, how do I define a function to print every single instance of the class in a format defined in the function?

I see two options in this case:在这种情况下,我看到两个选项:

Garbage collector垃圾收集器

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

This has the disadvantage of being very slow when you have a lot of objects, but works with types over which you have no control.当您有很多对象时,这具有非常慢的缺点,但适用于您无法控制的类型。

Use a mixin and weakrefs使用 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

In this case, all the references get stored as a weak reference in a list.在这种情况下,所有引用都作为弱引用存储在列表中。 If you create and delete a lot of instances frequently, you should clean up the list of weakrefs after iteration, otherwise there's going to be a lot of cruft.如果频繁创建和删除大量实例,则应在迭代后清理弱引用列表,否则会出现很多杂乱无章的情况。

Another problem in this case is that you have to make sure to call the base class constructor.这种情况下的另一个问题是您必须确保调用基类构造函数。 You could also override __new__ , but only the __new__ method of the first base class is used on instantiation.您也可以覆盖__new__ ,但只有第一个基类的__new__方法用于实例化。 This also works only on types that are under your control.这也仅适用于受您控制的类型。

Edit : The method for printing all instances according to a specific format is left as an exercise, but it's basically just a variation on the for -loops.编辑:根据特定格式打印所有实例的方法留作练习,但它基本上只是for循环的变体。

You'll want to create a static list on your class, and add a weakref to each instance so the garbage collector can clean up your instances when they're no longer needed.您需要在您的类上创建一个静态列表,并为每个实例添加一个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)

You don't need to import ANYTHING!你不需要导入任何东西! Just use "self".只需使用“自我”。 Here's how you do this这是你如何做到这一点

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

It's this simple.就是这么简单。 No modules or libraries imported没有导入模块或库

Very nice and useful code, but it has a big problem: list is always bigger and it is never cleaned-up, to test it just add print(len(cls.__refs__[cls])) at the end of the get_instances method.非常好的和有用的代码,但它有一个大问题:列表总是更大而且永远不会被清理,要测试它只需在get_instances方法的末尾添加print(len(cls.__refs__[cls]))

Here a fix for the get_instances method:这里修复了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

or alternatively it could be done using WeakSet:或者也可以使用 Wea​​kSet 来完成:

from weakref import WeakSet

__refs__ = defaultdict(WeakSet)

@classmethod
def get_instances(cls):
    return cls.__refs__[cls]

Same as almost all other OO languages, keep all instances of the class in a collection of some kind.与几乎所有其他 OO 语言一样,将类的所有实例保存在某种集合中。

You can try this kind of thing.你可以试试这种东西。

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

Now you can do this.现在你可以这样做了。

object= MyClassFactory( args, ... )
print MyClassFactory.theWholeList

Python doesn't have an equivalent to Smallktalk's #allInstances as the architecture doesn't have this type of central object table (although modern smalltalks don't really work like that either). Python 没有与 Smallktalk 的 #allInstances 等效的东西,因为架构没有这种类型的中央对象表(尽管现代 smalltalks 也不是那样工作的)。

As the other poster says, you have to explicitly manage a collection.正如另一张海报所说,您必须明确管理一个集合。 His suggestion of a factory method that maintains a registry is a perfectly reasonable way to do it.他提出的维护注册表的工厂方法是一种完全合理的方法。 You may wish to do something with weak references so you don't have to explicitly keep track of object disposal.您可能希望使用弱引用做一些事情,这样您就不必明确跟踪对象处理。

It's not clear if you need to print all class instances at once or when they're initialized, nor if you're talking about a class you have control over vs a class in a 3rd party library.不清楚您是否需要一次打印所有类实例或在它们初始化时打印,也不清楚您是否在谈论您可以控制的类与 3rd 方库中的类。

In any case, I would solve this by writing a class factory using Python metaclass support.无论如何,我会通过使用 Python 元类支持编写类工厂来解决这个问题。 If you don't have control over the class, manually update the __metaclass__ for the class or module you're tracking.如果您无法控制类,请手动更新您正在跟踪的类或模块的__metaclass__

See http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html for more information.有关更多信息,请参阅http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html

In my project, I faced a similar problem and found a simple solution that may also work for you in listing and printing your class instances.在我的项目中,我遇到了类似的问题,并找到了一个简单的解决方案,它也可以用于列出和打印类实例。 The solution worked smoothly in Python version 3.7;该解决方案在 Python 3.7 版本中运行顺利; gave partial errors in Python version 3.5.在 Python 3.5 版中给出了部分错误。

I will copy-paste the relevant code blocks from my recent project.我将从我最近的项目中复制粘贴相关代码块。

```
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}'

In Python the __str__ method in the end, determines how the object will be interpreted in its string form.在 Python 中,最后的__str__方法决定了对象将如何以其字符串形式被解释。 I added the : in between the curly brackets, they are completely my preference for a "Pandas DataFrame" kind of reading.我在大括号之间添加了: ,它们完全是我对“Pandas DataFrame”类型阅读的偏好。 If you apply this small __str__ function, you will not be seeing some machine-readable object type descriptions- which makes no sense for human eyes.如果您应用这个小的__str__函数,您将不会看到一些机器可读的对象类型描述——这对人眼来说毫无意义。 After adding this __str__ function you can append your objects to your list and print them as you wish.添加此__str__函数后,您可以将对象附加到列表中并根据需要打印它们。

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

For printing, your format in __str__ will work as default.对于打印,您在__str__的格式将作为默认值工作。 But it is also possible to call all attributes separately:但也可以单独调用所有属性:

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

For detailed reading, you may look at the source: https://dbader.org/blog/python-repr-vs-str详细阅读可以看源码: https : //dbader.org/blog/python-repr-vs-str

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM