1

Is there any way to get the object name when the class name is known. If there are multiple objects for a class they also need to be printed.

Class A():
   pass

Assume that some one have created objects for class A in some other files. So, I want to look all instances of 'Class A'

4
  • 1
    Can you add some code about what you are trying to do? I don't understand what you mean with object name in this context. Commented Sep 24, 2013 at 13:45
  • 4
    Do you mean to retrieve all instances of a given class? Commented Sep 24, 2013 at 13:47
  • I think you can find the answer here. Commented Sep 24, 2013 at 13:50
  • 1
    What do you mean by object name ? Commented Sep 24, 2013 at 13:50

7 Answers 7

2

If you are the one creating the class you can simply store weak-references when instantiating the class:

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]

Using weak-references allow the instances to be deallocated before the class.

See the weakref module for details on what it does.


Note that you may be able to use this technique even with classes that you didn't write. You simply have to monkey-patch the class. For example:

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

Then you can do:

track_instances(ExternalClass)

And all instances created after the execution of this statement will be found in ExternalClass.instances.

Depending on the class you may have to replace __new__ instead of __init__.


You can do this even without any special code in the class, simply using the garbage collector:

import gc

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

And you can always obtain the class object since you can find it using object.__subclasses__ method:

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

(assuming there is only a class with that name, otherwise you should try all of them)

However I cannot think of a situation where this is the right thing to do, so avoid this code in real applications.


I've done some testing and I believe that this solution may not work for built-in classes or classes defined in C extensions.

If you are in this case the last resort is to use gc.get_objects() to retrieve all tracked objects. However this will work only if the object support cyclic garbage collection, so there isn't a method that works in every possible situation.

Sign up to request clarification or add additional context in comments.

1 Comment

Good answer! I've updated mine to point at yours as it is better :-) I have some reading-up to do regarding the weakref module.
1

Here the version getting the instances from memory, I wouldn't recommend using this in live code but it can be convenient for debugging:

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'))

4 Comments

One issue with this approach is that every single of SomeClass ever created will exist forever (since the class keeps a reference to it).
Actually, object for that class is not created by me. As I know the class name i want to list the object(s) created for that class based on class name.
@Sobhan See my answer for that, but I strongly believe you just fell in the XY problem and you should have asked about your real problem and not your attempted solution.
@Sobhan: see the revised version :)
0

Python provides the types module that defined classes for built-in types and the locals() and globals() functions that return a list of local and global variables in the application.

One quick way to find objects by type is to do this.

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

It's worth going through the Python library documentation and read the docs for modules that work with the code directly. Some of which are inspect, gc, types, codeop, code, imp, ast. bdb, pdb. The IDLE source code is also very informative.

2 Comments

Two problems are that this won't find all references to all objects and you will find the same object multiple times if it has multiple references. You can add matching found objects to a set to handle the duplicate problem, but finding an object whose only references are fields in other objects seems like a harder problem.
True, this isn't the best way to do it. Using gc and weakref as suggested in one of the answers above is a better solution
0

Instances are created within a namespace:

def some_function():
    some_object = MyClass()

In this case, some_object is a name inside the "namespace" of the function that points at a MyClass instance. Once you leave the namespace (i.e., the function ends), Python's garbage collection cleans up the name and the instance.

If there would be some other location that also has a pointer to the object, the cleanup wouldn't happen.

So: no, there's no place where a list of instances is maintained.

It would be a different case where you to use a database with an ORM (object-relational mapper). In Django's ORM you can do MyClass.objects.all() if MyClass is a database object. Something to look into if you really need the functionality.

Update: See Bakuriu's answer. The garbage collector (which I mentioned) knows about all the instances :-) And he suggests the "weakref" module that prevents my won't-be-cleaned-up problem.

Comments

0

You cann get names for all the instances as they may not all have names, or the names they do have may be in scope. You may be able to get the instances.

If you are willing to keep track of the instances yourself, use a 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>]

Note that just deleting a name may not destroy the instance. other still exists until the garbage collected:

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

If you don't want to track them manually, then it is possible to use gc.get_objects() and filter out the instances you want, but that means you have to filter through all the objects in your program every time you do this. Even in the above example that means processing nearly 12,000 objects to find the 3 instances you want.

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

Comments

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

Comments

0

Finally found a way to get through.

As I know the class name, I would search for the object created for that class in garbage collector(gc) like this...

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

The above code returns an instance of the class which will be like this. Unfortunately,its in String format which doesn't suit the requirement. It should be of 'obj' type.

<mod_example.Sample object at 0x6f55250>

From the above value, parse the id(0x6f55250) and get the object reference based on the 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

Hence required_obj will hold the object reference exactly in the 'obj' format.

:-)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.