2

I have a very strange problem.

I need to return a class object to call a function that is supposed to return the class object that called it. I know, I know. Just think of it as a contrived exercise, though for me it is a very real need.

def baz():
    # return the object instance that calls me. 

class Foo():
    def bar(self, func):
        return func()  # should return the Foo object but how???

new_foo = Foo()
new_foo_instance = new_foo.bar(baz)

is it possible to write anything in baz() that will return the object that called it?

EDIT:

to answer the comments:

I have tried to use inspect, but with no success, I even looked at the entire stack but I cannot find an entry that matches the new_foo object:

new_foo looks like this when I printed it out: <__main__.Foo object at 0x0000029AAFC4C780>

when I printed out the entire stack that entry was not found within it:

def baz():
    print(inspect.stack())
    return inspect.stack() #[1][3]

>>> [FrameInfo(frame=<frame object at 0x0000029AADB49648>, filename='return_caller.py', lineno=5, function='baz', code_context=['    print(inspect.stack())\n'], index=0), FrameInfo(frame=<frame object at 0x0000029AAD8F0DE8>, filename='return_caller.py', lineno=11, function='bar', code_context=['        return func()  # should return the Foo object but how???\n'], index=0), FrameInfo(frame=<frame object at 0x0000029AAD8AC588>, filename='return_caller.py', lineno=19, function='<module>', code_context=['new_foo_instance = new_foo.bar(baz)\n'], index=0)]

So I am not trying to get it to return a new instance of Foo, but actually the exact same instance as new_foo.

MetaStack
  • 3,266
  • 4
  • 30
  • 67

2 Answers2

4

Use inspect:

import inspect

def baz():
    frame_infos = inspect.stack()  # A list of FrameInfo.
    frame = frame_infos[1].frame   # The frame of the caller.
    locs = frame.f_locals          # The caller's locals dict.
    return locs['self']

class Foo():
    def bar(self, func):
        return func()

f1 = Foo()
f2 = f1.bar(baz)
print(f1)
print(f2)
print(f2 is f1)  # True

Or cheat:

def baz():
    return getattr(baz, 'self', None)

class Foo():
    def bar(self, func):
        func.self = self  # Functions can be a place to store global information.
        return func()
FMc
  • 41,963
  • 13
  • 79
  • 132
1

The above answer is perfect and this is another way to fulfill your need.

import sys 
import inspect

def baz():
    """
    Return the object instance whose method calls me
    """
    for item in dir(sys.modules[__name__]):
        elem = eval(item)

        if inspect.isclass(elem):
            foo_instance = elem()
            break

    return foo_instance

class Foo():
    """
    Foo class
    """
    def bar(self, func):
        return func()  # should return the Foo object but how???

# Instantiation and calling
new_foo = Foo()
new_foo_instance = new_foo.bar(baz)

print(new_foo_instance)       # <__main__.Foo object at 0x0000015C5A2F59E8>
print(type(new_foo_instance)) # <class '__main__.Fo


# E:\Users\Rishikesh\Projects\Python3\try>python Get_caller_object_final.py
# <__main__.Foo object at 0x0000015C5A2F59E8>
# <class '__main__.Foo'>
References »
hygull
  • 8,464
  • 2
  • 43
  • 52