1

I tried to search the question for a bit but can't find a actual answer. I'm trying to implement a function (magic_debug) so that when called in another function (somefunc), it can access the variable within the somefunc and print it out as follow:

def magic_debug(s, *args, **kwargs):
    s2 = s.format(x=x,y=y,z=args[0])
    print(s2)


def somefunc():
    x = 123
    y = ['a', 'b']
    magic_debug('The value of x is {x}, and the list is {y} of len {z}', len(y))

somefunc()

the expected output --> The value of x is 123, and the list is ['a', 'b'] of len 2

10
  • 1
    Why don't you make you (somefunc) method return the value you want? If you need more that one value returned create a class or use a list. Commented Apr 4, 2018 at 1:44
  • Hi @PaulDavid ! This is actually an interview question I had earlier. So it need to be implemented via this way. Can you give me a hint on using class or list to solve this? Commented Apr 4, 2018 at 1:49
  • 1
    @LeonChen - Are you sure the question was posed exactly as above? If so, what modifications are allowed? Commented Apr 4, 2018 at 2:19
  • Hi @zwer I think any modification on magic_debug is okay. I think somefunc is fixed and shouldn't be changed. Commented Apr 4, 2018 at 2:31
  • @LeonChen - In that case, check Sraw's answer. Also, if I may offer a piece of unsolicited advice - run away from companies who ask such questions on an interview. Commented Apr 4, 2018 at 2:35

5 Answers 5

1

This is really a common question, try to use inspect.

def magic_debug(s, *args, **kwargs):
    import inspect
    parent_local_scope = inspect.currentframe().f_back.f_locals
    s2 = s.format(**parent_local_scope, z=args[0])
    print(s2)


def somefunc():
    x = 123
    y = ['a', 'b']
    magic_debug('The value of x is {x}, and the list is {y} of len {z}', len(y))

somefunc()

output:

The value of x is 123, and the list is ['a', 'b'] of len 2
Sign up to request clarification or add additional context in comments.

4 Comments

If magic_debug() can be changed inspect is quite a bit of an overkill - it's sufficient to pass locals() as expanded kwargs (magic_debug('The value of x is {x}, and the list is {y} of len {z}', len(y), **locals())) and then just re-expand it as: s.format(z=args[0], **kwargs) in the magic_debug().
Sure, you are right. But as I understand, the semantic meaning of this magic_debug is that I can access the parent's variables directly, and I want to accept some other parameters. That's difficult to say if it is a good idea and I just give what OP asked.
Thank you Sraw and zwer , it the task, I believe any modification to the magic_debug is acceptable. So I think Sraw's solution can solve this problem. zwer, can you elaborate more on your thought? I'm very interested in yours too!
@LeonChen - Ok, I've added the 'other' approach. It does require the change of the call to magic_debug() tho.
1

Do you mean it?

def magic_debug(s, vars_dict):

    s2 = s.format(**vars_dict)
    print(s2)


def somefunc():
   x = 123         # variables are indent in python
   y = ['a', 'b']  # so they're in the function scope

                   # and so is this function that somefunc calls - 
   vars_dict = vars()
   vars_dict['z'] = len(y)
   magic_debug('The value of x is {x}, and the list is {y} of len {z}', vars_dict)

somefunc()

Comments

1

If any modification is allowed as long as you keep the spirit of the question, you can use locals() to pass the local scope to the magic_debug function, i.e.:

def magic_debug(s, *args, **kwargs):
    s2 = s.format(z=args[0], **kwargs)
    print(s2)

def somefunc():
    x = 123
    y = ['a', 'b']
    magic_debug('The value of x is {x}, and the list is {y} of len {z}', len(y), **locals())

somefunc()
# The value of x is 123, and the list is ['a', 'b'] of len 2

And if you're allowed to change the function signatures you can pass the locals() without expansion, too. But if you cannot change the function being debugged, then peeking into the previous frame is the only way. @Sraw already covered that in his answer.

1 Comment

Much appreciated! @zwer , I believe the function being debugged can't be changed. Learn a lot in this hour from all the awesome responses :)
0

try this - you need to indent your function

def magic_debug(s, *args, **kwargs):

    s2 = s.format(x=x,y=y,z=args[0])
    print(s2)


def somefunc():
   x = 123         # variables are indent in python
   y = ['a', 'b']  # so they're in the function scope

                   # and so is this function that somefunc calls - 
   magic_debug('The value of x is {x}, and the list is {y} of len {z}', len(y))

somefunc()

3 Comments

thanks for the indentation, @Steven but I don't think magic_debug can access the x,y even with the indentation.
also 'The value of x is {0}, and the list is {1} of len {2}'.format(x,y,len(y)) should work
0

Change some of your code around to look like this:

def magic_debug(s, *args, **kwargs):
    s2 = s.format(x=args[1],y=kwargs.pop('y', ''),z=args[0])
    print(s2)


def somefunc():
    x = 123
    y = ['a', 'b']
    magic_debug('The value of x is {x}, and the list is {y} of len {z}', len(y), x, y=y)

somefunc()

Your output will be perfect. You're adding the **Kargs but you don't use it. The above code uses the **Karg to store the array.

Output:

The value of x is 123, and the list is ['a', 'b'] of len 2

Edit for fewer arguments:

def magic_debug(s, *args, **kwargs):
    s2 = s.format(x=args[1],y=args[0],z=len(args[0]))
    print(s2)


def somefunc():
    x = 123
    y = ['a', 'b']
    magic_debug('The value of x is {x}, and the list is {y} of len {z}', y, x)

somefunc()

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.