1

当类名已知时,有什么方法可以获取对象名。如果一个类有多个对象,则还需要打印它们。

Class A():
   pass

假设有人在其他文件中为类 A 创建了对象。所以,我想查看“A 类”的所有实例

4

7 回答 7

2

如果您是创建类的人,您可以在实例化类时简单地存储弱引用:

import weakref

class A(object):
    instances = []
    def __init__(self):
        A.instances.append(weakref.ref(self))

a, b, c = A(), A(), A()
instances = [ref() for ref in A.instances if ref() is not None]

使用弱引用允许在类之前释放实例。

有关其作用的详细信息,请参阅weakref模块。


请注意,即使使用不是您编写的类,您也可以使用此技术您只需要对课程进行猴子补丁即可。例如:

def track_instances(cls):
    def init(self, *args, **kwargs):
        getattr(self, 'instances').append(weakref.ref(self))
        getattr(self, '_old_init')(self, *args, **kwargs)
    cls._old_init = cls.__init__
    cls.__init__ = init
    return cls

然后你可以这样做:

track_instances(ExternalClass)

并且在执行此语句后创建的所有实例都将在ExternalClass.instances.

根据您可能需要替换的类__new__而不是__init__.


即使在类中没有任何特殊代码,您也可以这样做,只需使用垃圾收集器:

import gc

candidates = gc.get_referrers(cls_object)
instances = [candidate for candidate in candidates if isinstance(candidate, cls_object)]

而且您始终可以获取类对象,因为您可以使用object.__subclasses__以下方法找到它:

cls_object = next(cls for cls in object.__subclasses__() if cls.__name__ == cls_name)

(假设只有一个具有该名称的类,否则您应该尝试所有这些)

但是我想不出这是正确的做法,因此在实际应用程序中避免使用此代码


我做了一些测试,我相信这个解决方案可能不适用于内置类或 C 扩展中定义的类。

如果您在这种情况下,最后的手段是使用gc.get_objects()检索所有跟踪对象。但是,这仅在对象支持循环垃圾回收时才有效,因此没有一种方法适用于所有可能的情况。

于 2013-09-24T13:57:47.327 回答
1

这里是从内存中获取实例的版本,我不建议在实时代码中使用它,但它可以方便调试:

import weakref


class SomeClass(object):
    register = []

    def __init__(self):
        self.register.append(weakref.ref(self))

a = SomeClass()
b = SomeClass()
c = SomeClass()

# Now the magic :)
import gc


def get_instances(class_name):
    # Get the objects from memory
    for instance in gc.get_objects():
        # Try and get the actual class
        class_ = getattr(instance, '__class__', None)
        # Only return if the class has the name we want
        if class_ and getattr(class_, '__name__', None) == class_name:
            yield instance

print list(get_instances('SomeClass'))
于 2013-09-24T13:50:58.307 回答
0

实例在命名空间内创建:

def some_function():
    some_object = MyClass()

在这种情况下,some_object是指向MyClass实例的函数的“命名空间”内的名称。一旦您离开命名空间(即函数结束),Python 的垃圾回收器就会清理名称和实例。

如果还有一些其他位置也有指向该对象的指针,则不会发生清理。

所以:不,没有地方维护实例列表。

如果您将数据库与 ORM(对象关系映射器)一起使用,那将是另一种情况。MyClass.objects.all()在 Django 的 ORM 中,如果 MyClass 是数据库对象,您可以这样做。如果您真的需要该功能,可以研究一下。

更新:见Bakuriu 的回答。垃圾收集器(我提到的)知道所有实例 :-) 他建议使用“weakref”模块来防止我无法清理的问题。

于 2013-09-24T13:54:07.627 回答
0

您无法获取所有实例的名称,因为它们可能并非都具有名称,或者它们确实具有的名称可能在范围内。您也许可以获得实例。

如果您愿意自己跟踪实例,请使用 Wea​​kSet:

import weakref
class SomeClass(object):
instances = weakref.WeakSet()
def __init__(self):
    self.instances.add(self)


>>> instances = [SomeClass(), SomeClass(), SomeClass()]
>>> other = SomeClass()
>>> SomeClass.instances
<_weakrefset.WeakSet object at 0x0291F6F0>
>>> list(SomeClass.instances)
[<__main__.SomeClass object at 0x0291F710>, <__main__.SomeClass object at 0x0291F730>, <__main__.SomeClass object at 0x028F0150>, <__main__.SomeClass object at 0x0291F210>]

请注意,仅删除名称可能不会破坏实例。other在垃圾收集之前仍然存在:

>>> del other
>>> list(SomeClass.instances)
[<__main__.SomeClass object at 0x0291F710>, <__main__.SomeClass object at 0x0291F730>, <__main__.SomeClass object at 0x028F0150>, <__main__.SomeClass object at 0x0291F210>]
>>> import gc
>>> gc.collect()
0
>>> list(SomeClass.instances)
[<__main__.SomeClass object at 0x0291F710>, <__main__.SomeClass object at 0x0291F730>, <__main__.SomeClass object at 0x0291F210>]

如果您不想手动跟踪它们,则可以使用gc.get_objects()并过滤掉您想要的实例,但这意味着您每次执行此操作时都必须过滤程序中的所有对象。即使在上面的示例中,这也意味着要处理近 12,000 个对象以找到您想要的 3 个实例。

>>> [g for g in gc.get_objects() if isinstance(g, SomeClass)]
[<__main__.SomeClass object at 0x0291F210>, <__main__.SomeClass object at 0x0291F710>, <__main__.SomeClass object at 0x0291F730>]
于 2013-09-24T14:02:00.780 回答
0

Python 提供了types为内置类型定义类的模块,locals()以及globals()返回应用程序中的局部和全局变量列表的函数。

按类型查找对象的一种快速方法是执行此操作。

import types

for varname, var_instance in locals().items():
  if type(var_instance) == types.InstanceType and var_instance.__class__.__name__ == 'CLASS_NAME_YOU_ARE_LOOKING_FOR':
    print "This instance was found:", varname, var_instance

值得阅读 Python 库文档并阅读直接使用代码的模块的文档。其中一些是inspect, gc, types, codeop, code, imp, ast. bdb, pdb. IDLE 源代码也非常有用。

于 2013-09-24T13:59:08.460 回答
0

终于找到通关的方法了。

因为我知道类名,所以我会像这样在垃圾收集器(gc)中搜索为该类创建的对象......

for instance in gc.get_objects():

            if str(type(instance)).find("dict") != -1:

                for k in instance.keys():

                    if str(k).find("Sample") != -1:

                        return k

上面的代码返回一个类的实例,如下所示。不幸的是,它的字符串格式不符合要求。它应该是“obj”类型。

<mod_example.Sample object at 0x6f55250>

从上面的值,解析id(0x6f55250),根据id得到对象引用。

obj_id = 0x6f55250
for obj in gc.get_objects():
            # Converting decimal value to hex value
            if id(obj) == ast.literal_eval(obj_id):
                required_obj = obj

因此 required_obj 将完全以“obj”格式保存对象引用。

:-)

于 2013-10-03T10:13:07.617 回答
0
>>> class TestClass:
...     pass
... 
>>> foo = TestClass()
>>> for i in dir():
...     if isinstance(eval(i), TestClass):
...             print(i)
... 
foo
>>> 
于 2013-09-24T13:52:06.910 回答