Introspect calling object

12,478

Solution 1

In general we don't want that func to have access back to the calling instance of A because this breaks encapsulation. Inside of b.func you should have access to any args and kwargs passed, the state/attributes of the instance b (via self here), and any globals hanging around.

If you want to know about a calling object, the valid ways are:

  1. Pass the calling object in as an argument to the function
  2. Explicitly add a handle to the caller onto b instance sometime before using func, and then access that handle through self.

However, with that disclaimer out of the way, it's still worth knowing that python's introspection capabilities are powerful enough to access the caller module in some cases. In the CPython implementation, here is how you could access the calling A instance without changing your interfaces:

class A():
    def go(self):
        b=B()
        b.func()

class B():
    def func(self):
        import inspect
        print inspect.currentframe().f_back.f_locals['self']

if __name__ == '__main__':
    a = A()
    a.go()

Output:

<__main__.A instance at 0x15bd9e0>

This might be a useful trick to know about for debugging code sometimes. But it would not be a sensible design decision to ever access the stack frames like this in the case that B.func actually needed to use A for any reason.

Solution 2

You pass it to b.func() as an argument.

Solution 3

Do this by refactoring your code to work like

class A():
    def go(self):
        b = B(self)
        b.func()

class B():
    def __init__(self, a):
        self.a = a

    def func(self):
        # Use self.a

or

class A():
    def go(self):
        b = B()
        b.func(self)

class B():
    def func(self, a):
        # a
Share:
12,478

Related videos on Youtube

Jonathan Livni
Author by

Jonathan Livni

python, django, C++ and other vegetables...

Updated on June 04, 2022

Comments

  • Jonathan Livni
    Jonathan Livni about 2 years

    How do I introspect A's instance from within b.func() (i.e. A's instance's self):

    class A():
        def go(self):
            b=B()
            b.func()
    
    class B():
        def func(self):
            # Introspect to find the calling A instance here
    
  • Jonathan Livni
    Jonathan Livni almost 13 years
    Actually there are many As that may call B's instance. I wouldn't like to keep them all in B's instance
  • Mike Graham
    Mike Graham almost 13 years
    This is fragile (there are plenty of cases we could construct with which it does not work) and non-portable (inspect.currentframe is an implementation detail).
  • Mike Graham
    Mike Graham almost 13 years
    @Johnathan, In the example snippet, Bs were made by an A, and it wasn't clear they were kept and used by many different As. It sounds like you may want to pass the right A precisely when you cal B.func, like in my second example.
  • wim
    wim almost 13 years
    the OP asked for Introspection. this is the only way i know how to do it without changing their interfaces.
  • Mike Graham
    Mike Graham almost 13 years
    It turns out the OP didn't need introspection and could and did implement a sane API. The important thing isn't obeying the question as asked; the important thing is helping the person asking.
  • Nick Perkins
    Nick Perkins almost 13 years
    +1 for answering the question as asked ( regardless of whether it is wise to do it this way ). Where will this not work? I suspect the "disclaimer" about currentframe() is alluding to Stackless ( not to Jython or Iron Python )....can anyone confirm this?
  • wim
    wim almost 13 years
    @Mike simple example of a situation where this knowledge might be helping the person asking: code crashed in body of B.func. user invokes debugger and wants to inspects some attributes of the caller module. it doesn't necessarily have to be about implementing a sane API or not. if it was a n00b maybe I would explain more, but in this case the OP's reputation is higher than my own.
  • Mike Graham
    Mike Graham almost 13 years
    @wim, in that case the person wants to use pdb, not to rewrite their code to have a half-baked implementation of pdb interspersed in the application.
  • wim
    wim almost 13 years
    @Mike you're missing the point, i'm not saying you rewrite you code instead of pdb. suppose you are in ipython, and you get an unhandled exception in B.func. then you can use the magic %debug and you're in the body of func. from there you have the full power of the interpreter, and you could type import inspect and do whatever introspection might help you. just because a tool can be abused it doesn't mean it should never be used
  • Mike Graham
    Mike Graham almost 13 years
    @wim, I never made a claim that inspect.currentframe should never be used. I did claim, and still believe, that this solution does not help the original poster.
  • wim
    wim almost 13 years
    @Mike I am not going to have this argument with you. It's up to the asker whether this knowledge is helpful or not for their particular situation. Perhaps you should read the title of this question again.
  • Wilduck
    Wilduck almost 13 years
    @wim Actually, it's up to the community whether this knowledge is helpful to more than just the poster. That's why it's getting downvotes. These are a signal that what you posted is a poor solution for the OP to use.
  • wim
    wim almost 13 years
    @Wilduck you can not say what the 'solution' is when the problem has not been defined. they have simply asked for introspection, the question is even tagged python introspection - and i can't see any other answer here which actually does introspection. i can only guess the downvotes are due to it not being made clear how/why the function being aware of it's caller is in poor taste, which might lead other people reading the answer to misuse and abuse pythons introspection powers. i'll edit my answer to make that matter more clear and see if any of the downvotes get changed.
  • Mike Graham
    Mike Graham almost 13 years
    @wim, Clearly this escalated a bit from this narrow discussion. If you'd like to discuss our interactions and ideas of how to make SO the best resource it can be, I started a room at chat.stackoverflow.com/rooms/3077/room-for-mike-graham-and-w‌​im
  • Nick Perkins
    Nick Perkins almost 13 years
    I find this all astonishing. Do people think that Python's ability to do introspection should be kept secret just because it's usually not the right thing to do? Only one answer gave the right facts, and people downvote it? Facts are facts. Do the downvoters object to revealing this "secret knowlege"? You all have no idea why the OP is looking for this, and therefore you can not judge that it is wrong. There are certainly possible situations where this type of introspection would be valuable. So, imho, ok to warn against it, but should not downvote ans for revealing how it can be done.
  • Pithikos
    Pithikos over 9 years
    Sometimes this is the only way to solve an issue actually and I don't see why people seem to ignore this. What if you want to have a generic function fatal_error(msg) for example which shows the caller? I'm pretty sure you don't want to call fatal_error(obj, msg)