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

Leon Chen
  • 145
  • 2
  • 7
  • 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. – Smitty-Werben-Jager-Manjenson Apr 04 '18 at 01: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? – Leon Chen Apr 04 '18 at 01:49
  • 1
    @LeonChen - Are you sure the question was posed exactly as above? If so, what modifications are allowed? – zwer Apr 04 '18 at 02:19
  • Hi @zwer I think any modification on magic_debug is okay. I think somefunc is fixed and shouldn't be changed. – Leon Chen Apr 04 '18 at 02: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. – zwer Apr 04 '18 at 02:35
  • See my answer below... Minimal code change and formatting – Smitty-Werben-Jager-Manjenson Apr 04 '18 at 02:40
  • @zwer Haha! thanks for the advice. Is it because this is too trivial? Probably didn't get the offer anyway :( – Leon Chen Apr 04 '18 at 02:46
  • The question is worded strangely. if you want to "access the variable" you'd add "return yourVariable" at the bottom of the magic_debug() method. If you're just looking to get the desired output, most of the answers below will do the trick – Smitty-Werben-Jager-Manjenson Apr 04 '18 at 02:50
  • @LeonChen - It's not trivial, it's a _gotcha_ question where an interviewer (or whoever designed the interview questions) tries to pry out of you a piece of potentially obscure knowledge that you most likely won't ever need while working for them and, even if you do, its a few Google searches away. No company worth working for tries to work against their employees, present or future ones, by holding a language and standard library reference over their heads, but I digress... – zwer Apr 04 '18 at 02:55
  • @zwer I see your point. Yeah, this one got me pretty bad. Multiple try without success. But I'm glad to have all the constructive support on this one. <3 – Leon Chen Apr 04 '18 at 03:07

5 Answers5

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
Sraw
  • 18,892
  • 11
  • 54
  • 87
  • 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()`. – zwer Apr 04 '18 at 02:17
  • 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. – Sraw Apr 04 '18 at 02:23
  • 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! – Leon Chen Apr 04 '18 at 02:36
  • @LeonChen - Ok, I've added the 'other' approach. It does require the change of the call to `magic_debug()` tho. – zwer Apr 04 '18 at 02:42
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()
0811张庆昊
  • 538
  • 4
  • 16
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.

zwer
  • 24,943
  • 3
  • 48
  • 66
  • Much appreciated! @zwer , I believe the function being debugged can't be changed. Learn a lot in this hour from all the awesome responses :) – Leon Chen Apr 04 '18 at 02:51
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()
Steven Black
  • 1,988
  • 1
  • 15
  • 25
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()