9

I'm trying to find out, at runtime, where an object has been instantiated, as this would enable providing a very useful error message to users of my library.

Suppose we have the following code:

import mylib

obj = mylib.MyClass()

obj is then passed to an instance of another class from mylib, and proceeds on a wonderful journey. Somewhere along the line, obj causes something bad to happen, and I'd like to point the user to where obj was instantiated.

I was hoping I could use the inspect module to find out in which file and at what line number obj was instantiated. Unfortunately, the inspect.getsourcefile and inspect.getsourcelines do not support instances. Is there a technical reason why this is not supported?

Is there another way I can obtain the data I'm looking for?

Brecht Machiels
  • 3,181
  • 3
  • 25
  • 38
  • isn't that overcomplicated? when something bad happens, why not do what we all (presumably) do? As in: import traceback + try: ... except: traceback.print_exc() – StefanNch Jan 19 '13 at 10:09

2 Answers2

9

You could record this information in your class's constructor:

import traceback

class MyClass(object):
   def __init__(self):
       self.traceback = traceback.extract_stack()[-2]

obj = MyClass()

print 'Instantiated in {0}:{1}'.format(*obj.traceback)
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Unfortunately this doesn't work so well for subclasses, as each level of inheritance is a new stack frame and it may not be constant for every object concerned. So some extra logic to determine how many frames to go back may be required. This becomes even more complicated when multiple inheritance is involved. – davidA Mar 28 '17 at 22:15
0

may be you want this??

In [1]: def checkinstance(prohibitedclass):
   ...:     import sys
   ...:     final_result=set()
   ...:     for x in sys._getframe(1).f_locals:
   ...:         if isinstance(sys._getframe(1).f_locals.get(x),prohibitedclass):
   ...:             final_str="instance of class %s is at: %s"%(prohibitedclass,sys._getframe(1).f_locals.get(x))
   ...:             final_result.add(final_str)
   ...:     return list(final_result)

In [2]: class not_allowedclass(object):
   ...:     pass

In [3]: checkinstance(not_allowedclass)
Out[3]: []

In [4]: nk=not_allowedclass()

In [5]: nk1=not_allowedclass()

In [6]: checkinstance(not_allowedclass)
Out[6]: 
["instance of class <class '__main__.not_allowedclass'> is at: <__main__.not_allowedclass object at 0x102dcdb10>",
 "instance of class <class '__main__.not_allowedclass'> is at: <__main__.not_allowedclass object at 0x102dcda90>"]

In [7]: nk
Out[7]: <__main__.not_allowedclass at 0x102dcda90>

In [8]: nk1
Out[8]: <__main__.not_allowedclass at 0x102dcdb10>

In [9]: 
namit
  • 6,780
  • 4
  • 35
  • 41