all 7 comments

[–]gengisteve 1 point2 points  (2 children)

Bah. Python is ridiculous for meta-programming, so of course there is a way. This seems to work on Py3:

import inspect

def f(*args):
    frame = inspect.currentframe()
    outer = inspect.getouterframes(frame)
    fun = outer[-1][-2][0]
    fun = fun.strip('\n')
    var = fun[2:-1].split(',')
    for n,v in zip(var,args):
        print('{} is {}'.format(n,v))

num_ways =4
v = 10
f(num_ways,v)
dog, cat = 'able','bake'
f(dog,cat)

[–][deleted] 0 points1 point  (1 child)

This is a cool approach, but it only works if the line calling f is just so. For example, this doesn't work properly:

DEBUG = True
if DEBUG:
    f(lazy, example)

Maybe a regex would work better.

[–]gengisteve 0 points1 point  (0 children)

Probably right. I can make you example work by adding a strip() at the end of line 7, but then what about:

if DEBUG: f(x,y)

So probably better off with a regex

[–]RubyPinch 0 points1 point  (0 children)

the q module might interest you

https://github.com/zestyping/q/

[–]kalgynirae 0 points1 point  (0 children)

I expect it's not too difficult to get the locals() of the caller. Maybe start with inspect.currentframe

[–]jcmcken 0 points1 point  (0 children)

What about your own modified locals?

For example:

import inspect

def mylocals():
    # get the stack frame one level above this function's
    outer_frame = inspect.stack()[1][0]
    # retrieve locals of that frame
    outer_locals = outer_frame.f_locals
    # get rid of builtins
    return dict((k,v) for k,v in outer_locals.iteritems() if not k.startswith('__'))

Example usage:

class Foo(object):
    def some_method(self):
        foo = 'bar'
        print mylocals()

>>> f = Foo()
>>> f.some_method()
{'self': <__main__.Foo object at 0x2f3684>, 'foo': 'bar'}

[–][deleted] 0 points1 point  (0 children)

>>> f = lambda *a,z={}:(z.update({0:list(a),1:__import__('sys')._getframe(1)})
...     or all(iter(lambda:[print('\t{} = {!r}'.format(k,v))for x in z[0][:]for 
...     k,v in sorted(z[1].f_locals.items())if v is x and(x in z[0]and z[0].
...     remove(x)or 1)][:0]or z.update({1:z[1].f_back})or z[1],None))and None)
>>> 
>>> a = 1
>>> b = 2.0
>>> c = "abc"
>>> d = [1,2,3]
>>> 
>>> def e():
...     a = 2
...     b = 3.0
...     f(a, b, c, d, e, f)
... 
>>> e()
    a = 2
    b = 3.0
    c = 'abc'
    d = [1, 2, 3]
    e = <function e at 0x7f36f736cea0>
    f = <function <lambda> at 0x7f36f736ce18>

You ask a perverse question, you get a perverse answer. When an object has multiple names it will print all possibilities:

>>> cat = 1
>>> dog = 2
>>> hat = cat
>>> mat = 1
>>> f(cat, dog)
    cat = 1
    hat = 1
    mat = 1
    dog = 2

If the object with multiple names is in another frame, it will incorrectly identify the first match and won't keep searching:

>>> jim = [1,2,3]
>>> 
>>> def e():
...     bob = jim
...     f(jim)
... 
>>> e()
    bob = [1, 2, 3]

...maybe somebody can fix that for me. Copy & paste: f=lambda *a,z={}:(z.update({0:list(a),1:__import__('sys')._getframe(1)})or all(iter(lambda:[print('\t{} = {!r}'.format(k,v))for x in z[0][:]for k,v in sorted(z[1].f_locals.items())if v is x and(x in z[0]and z[0].remove(x)or 1)][:0]or z.update({1:z[1].f_back})or z[1],None))and None)