如何在当前模块中获取一个类的所有实例

3

我有一个名为foo的模块,它定义了一个类Foo并实例化了多个该类的对象。

在其他模块中,我可以通过import foo导入该模块,并通过以下方式获取已实例化的Foo对象列表:

[getattr(foo,f) for f in dir(f) if isinstance(getattr(foo,f), foo.Foo)]

如果我能在模块foo内部完成这个操作将会非常方便。但是按照当前的写法,在foo内使用名称foo没有意义,而改为使用self也无济于事。

有没有一种方法可以在该模块内使用内省来查找此类的所有实例?我希望能够避免制作列表并附加每个实例的方式。


1
我建议将其重命名为“如何获取类的所有实例”,假设这就是你想要做的。 - ninjagecko
1个回答

8

目标: "import foo 并获得由...实例化的 Foo 对象列表..."

你根本不需要反射。想象一下这是你的类:

class Registered(object):
    _all = set()
    def __init__(self):
        self.__class__._all.add(self)

示例:实例化一些对象并引用它们:

>>> Registered()
>>> Registered()
>>> Registered()

>>> Registered._all
{<__main__.Registered object at 0xcd3210>, <__main__.Registered object at 0xcd3150>, <__main__.Registered object at 0xcd31d0>}

由于您使用了dir,如果我理解正确,您正在尝试查找当前模块全局变量中的所有对象。但这实际上并不能让您获得当前模块中的所有对象,只能获得与变量绑定的对象。如果这是您真正想要的,可以使用 {var for name,var in globals() if isinstance(var,Foo)}
如果这不是您真正想要的,您可以修改上面的代码,通过inspect.currentframe().f_back.f_globals或其他方式跟踪定义对象的模块,但这将阻止您使用在foo.py或其他模块中定义的工厂函数。
如果您实际上想要获取在模块中创建的所有实例,这表明存在严重的编码问题。请考虑在该模块中编写一个工厂函数包装器,该包装器什么也不做,只传递初始化参数并返回结果,并跟踪已初始化的对象。

当我尝试这个时,我得到了NameError: global name '__class__' is not defined的错误。 - Eric Wilson
1
你可以使用 type(self)。或者改写 __new__ 方法。 - Cat Plus Plus
只要不对self.__all__进行赋值,它将与Registered.__all__相同。此外,__all__是一个糟糕的名称。它应该被命名为_all__all,以两个下划线开头和结尾的名称是Python保留用于未来定义的,而且由于__all__在Python中没有特定的用途,因此它不应匹配保留模式。 - SingleNegationElimination
3
我建议在集合中使用弱引用来存储对象,否则将很难对它们进行回收。 - Dietrich Epp
@Dietrich:非常好的想法!非常感谢。@TokenMacGuy:你说得对,也许最好做一些像初始化这样的东西,如果not hasattr(__class__,'registry'),那么__class__.registry.add(...),并且它与在__init__.py文件中使用__all__发生冲突。我不太介意,但这是一个有效的问题,我没有提到。 - ninjagecko
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接