如何在Python中获取给定类名的对象?

时间:2013-09-24 13:40:32

标签: python

在知道类名时是否有任何方法可以获取对象名称。如果一个类有多个对象,则还需要打印它们。

Class A():
   pass

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

7 个答案:

答案 0 :(得分: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模块。


请注意,即使您没有编写的类,也可以使用此技术。你只需要 monkey-patch 这个类。 例如:

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()来检索所有跟踪的对象。但是,这仅在对象支持循环垃圾收集时才有效,因此没有一种方法可以在每个可能的情况下工作。

答案 1 :(得分: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'))

答案 2 :(得分:0)

>>> class TestClass:
...     pass
... 
>>> foo = TestClass()
>>> for i in dir():
...     if isinstance(eval(i), TestClass):
...             print(i)
... 
foo
>>> 

答案 3 :(得分:0)

在命名空间中创建实例:

def some_function():
    some_object = MyClass()

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

如果某个其他位置也有指向该对象的指针,则不会进行清理。

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

将数据库与ORM(对象关系映射器)一起使用将是一种不同的情况。在Django的ORM中,如果MyClass是数据库对象,则可以MyClass.objects.all()。如果你真的需要这个功能,可以考虑一下。

更新:请参阅Bakuriu's answer。垃圾收集器(我提到过)知道所有实例:-)而且他建议使用“weakref”模块来阻止我不会被清理的问题。

答案 4 :(得分: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库文档并阅读直接使用代码的模块的文档。其中一些是inspectgctypescodeopcodeimpastbdbpdb。 IDLE源代码也非常有用。

答案 5 :(得分:0)

你可以获得所有实例的名称,因为它们可能都没有名称,或者它们所拥有的名称可能在范围内。您可以获得实例。

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

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>]

答案 6 :(得分: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

上面的代码返回类的实例,它将是这样的。不幸的是,它的String格式不符合要求。它应该是'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'格式保存对象引用。

: - )