当类名已知时,有什么方法可以获取对象名。如果一个类有多个对象,则还需要打印它们。
Class A():
pass
假设有人在其他文件中为类 A 创建了对象。所以,我想查看“A 类”的所有实例
当类名已知时,有什么方法可以获取对象名。如果一个类有多个对象,则还需要打印它们。
Class A():
pass
假设有人在其他文件中为类 A 创建了对象。所以,我想查看“A 类”的所有实例
如果您是创建类的人,您可以在实例化类时简单地存储弱引用:
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()
检索所有跟踪对象。但是,这仅在对象支持循环垃圾回收时才有效,因此没有一种方法适用于所有可能的情况。
这里是从内存中获取实例的版本,我不建议在实时代码中使用它,但它可以方便调试:
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'))
实例在命名空间内创建:
def some_function():
some_object = MyClass()
在这种情况下,some_object
是指向MyClass
实例的函数的“命名空间”内的名称。一旦您离开命名空间(即函数结束),Python 的垃圾回收器就会清理名称和实例。
如果还有一些其他位置也有指向该对象的指针,则不会发生清理。
所以:不,没有地方维护实例列表。
如果您将数据库与 ORM(对象关系映射器)一起使用,那将是另一种情况。MyClass.objects.all()
在 Django 的 ORM 中,如果 MyClass 是数据库对象,您可以这样做。如果您真的需要该功能,可以研究一下。
更新:见Bakuriu 的回答。垃圾收集器(我提到的)知道所有实例 :-) 他建议使用“weakref”模块来防止我无法清理的问题。
您无法获取所有实例的名称,因为它们可能并非都具有名称,或者它们确实具有的名称可能在范围内。您也许可以获得实例。
如果您愿意自己跟踪实例,请使用 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>]
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 源代码也非常有用。
终于找到通关的方法了。
因为我知道类名,所以我会像这样在垃圾收集器(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”格式保存对象引用。
:-)
>>> class TestClass:
... pass
...
>>> foo = TestClass()
>>> for i in dir():
... if isinstance(eval(i), TestClass):
... print(i)
...
foo
>>>