如何跟踪类实例?

新手上路,请多包涵

在程序结束时,我希望将某个类的所有实例中的特定变量加载到字典中。

例如:

 class Foo():
    def __init__(self):
        self.x = {}

foo1 = Foo()
foo2 = Foo()
...

假设实例的数量会有所不同,我希望将每个 Foo() 实例的 x 字典加载到新字典中。我该怎么做?

我在 SO 中看到的示例假设已经有实例列表。

原文由 DBWeinstein 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 440
2 个回答

跟踪实例的一种方法是使用类变量:

 class A(object):
    instances = []

    def __init__(self, foo):
        self.foo = foo
        A.instances.append(self)

在程序结束时,您可以像这样创建字典:

 foo_vars = {id(instance): instance.foo for instance in A.instances}

只有一个列表:

 >>> a = A(1)
>>> b = A(2)
>>> A.instances
[<__main__.A object at 0x1004d44d0>, <__main__.A object at 0x1004d4510>]
>>> id(A.instances)
4299683456
>>> id(a.instances)
4299683456
>>> id(b.instances)
4299683456

原文由 Joel Cornett 发布,翻译遵循 CC BY-SA 3.0 许可协议

@JoelCornett 的回答完美地涵盖了基础知识。这是一个稍微复杂的版本,可能有助于解决一些微妙的问题。

如果您希望能够访问给定类的所有“实时”实例,请将以下子类化(或在您自己的基类中包含等效代码):

 from weakref import WeakSet

class base(object):
    def __new__(cls, *args, **kwargs):
        instance = object.__new__(cls, *args, **kwargs)
        if "instances" not in cls.__dict__:
            cls.instances = WeakSet()
        cls.instances.add(instance)
        return instance

这解决了@JoelCornett 提出的更简单实现的两个可能问题:

  1. base 的每个子类将分别跟踪自己的实例。您不会在父类的实例列表中获得子类实例,并且一个子类永远不会偶然发现同级子类的实例。这可能是不可取的,具体取决于您的用例,但将这些集合重新合并在一起可能比将它们分开更容易。

  2. instances 集合使用对类实例的弱引用,所以如果你 del 或将所有其他引用重新分配给代码中其他地方的实例,簿记代码不会阻止它被收集的垃圾。同样,这对于某些用例来说可能并不理想,但如果您真的希望每个实例都永远持续下去,那么使用常规集(或列表)而不是弱集就足够容易了。

一些方便的测试输出( instances 设置总是被传递到 list 只是因为它们不能很好地打印出来):

 >>> b = base()
>>> list(base.instances)
[<__main__.base object at 0x00000000026067F0>]
>>> class foo(base):
...     pass
...
>>> f = foo()
>>> list(foo.instances)
[<__main__.foo object at 0x0000000002606898>]
>>> list(base.instances)
[<__main__.base object at 0x00000000026067F0>]
>>> del f
>>> list(foo.instances)
[]

原文由 Blckknght 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题