I like to know what was the local variable names when they are passed to a function. I\'m not sure whether this is possible at all. Let\'s consider this example:
fun
It seems that it's impossible in Python but it's actually possible in C++.
#define show(x) std::cout << #x << " = " << x << std::endl
No, you cannot know what the name was of the local variable used to pass a value to your function.
This is an impossible task in any case. What would be the variable name in the following example?
arguments = ('a', 1, 10)
somefunction(*(arguments[:2] + [10]))
Here we pass in 3 arguments, two taken from a tuple we defined earlier, and one literal value, and all three are passed in using the variable argument list syntax.
New Solution Using readline
If you're in an interactive session, here's an extremely naive solution that will usually work:
def show(x):
from readline import get_current_history_length, get_history_item
print(get_history_item(get_current_history_length()).strip()[5:-1] + ' = ' + str(x))
All it does is read the last line input in the interactive session buffer, remove any leading or trailing whitespace, then give you everything but the first five characters (hopefully show(
) and the last character (hopefully )
), thus leaving you with whatever was passed in.
Example:
>>> a = 10
>>> show(a)
a = 10
>>> b = 10
>>> show(b)
b = 10
>>> show(10)
10 = 10
>>> show([10]*10)
[10]*10 = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
>>> show('Hello' + 'World'.rjust(10))
'Hello' + 'World'.rjust(10) = Hello World
If you're on OS X using the version of Python that comes with it, you don't have readline
installed by default, but you can install it via pip
. If you're on Windows, readline
doesn't exist for you... you might be able to use pyreadline
from pip
but I've never tried it so I can't say if it's an acceptable substitute or not.
I leave making the above code more bullet-proof as an exercise for the reader. Things to consider would be how to make it handle things like this:
show(show(show(10)))
show(
10
)
If you want this kind of thing to show variables names from a script, you can look into using inspect and getting the source code of the calling frame. But given I can't think of why you would ever want to use show()
in a script or why you would complicate the function just to handle people intentionally screwing with it as I did above, I'm not going to waste my time right now figuring it out.
Original Solution Using inspect
Here's my original solution, which is more complicated and has a more glaring set of caveats, but is more portable since it only uses inspect
, not readline
, so runs on all platforms and whether you're in an interactive session or in a script:
def show(x):
from inspect import currentframe
# Using inspect, figure out what the calling environment looked like by merging
# what was available from builtin, globals, and locals.
# Do it in this order to emulate shadowing variables
# (locals shadow globals shadow builtins).
callingFrame = currentframe().f_back
callingEnv = callingFrame.f_builtins.copy()
callingEnv.update(callingFrame.f_globals)
callingEnv.update(callingFrame.f_locals)
# Get the variables in the calling environment equal to what was passed in.
possibleRoots = [item[0] for item in callingEnv.items() if item[1] == x]
# If there are none, whatever you were given was more than just an identifier.
if not possibleRoots:
root = '<unnamed>'
else:
# If there is exactly one identifier equal to it,
# that's probably the one you want.
# This assumption could be wrong - you may have been given
# something more than just an identifier.
if len(possibleRoots) == 1:
root = str(possibleRoots[0])
else:
# More than one possibility? List them all.
# Again, though, it could actually be unnamed.
root = '<'
for possibleRoot in possibleRoots[:-1]:
root += str(possibleRoot) + ', '
root += 'or ' + str(possibleRoots[-1]) + '>'
print(root + ' = ' + str(x))
Here's a case where it works perfectly (the one from the question):
>>> a = 10
>>> show(a)
a = 10
Here's another fun case:
>>> show(quit)
quit = Use quit() or Ctrl-Z plus Return to exit
Now you know how that functionality was implemented in the Python interpreter - quit
is a built-in identifier for a str
that says how to properly quit.
Here's a few cases where it's less than you might want, but... acceptable?
>>> b = 10
>>> show(b)
<a, or b> = 10
>>> show(11)
<unnamed> = 11
>>> show([a])
<unnamed> = [10]
And here's a case where it prints out a true statement, but definitely not what you were looking for:
>>> show(10)
<a, or b> = 10
I like the answer to this question that's found in the Python programming FAQ, quoting Fredrik Lundh:
The same way as you get the name of that cat you found on your porch: the cat (object) itself cannot tell you its name, and it doesn’t really care – so the only way to find out what it’s called is to ask all your neighbours (namespaces) if it’s their cat (object)...
....and don’t be surprised if you’ll find that it’s known by many names, or no name at all!
Not exactly like this. However, you can achieve something similar:
def show(**kwargs):
print(', '.join('%s=%s' % kv for kv in kwargs.items()))
show(a=20)
I forebode that the following solution will gain several criticisms
def show(*x):
for el in x:
fl = None
for gname,gobj in globals().iteritems():
if el==gobj:
print '%s == %r' % (gname,el)
fl = True
if not fl:
print 'There is no identifier assigned to %r in the global namespace' % el
un = 1
y = 'a'
a = 12
b = c = 45
arguments = ('a', 1, 10)
lolo = [45,'a',a,'heat']
print '============================================'
show(12)
show(a)
print '============================================'
show(45)
print
show(b)
print '============================================'
show(arguments)
print
show(('a', 1, 10))
print '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'
show(*arguments)
print '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'
show(*(arguments[1:3] + (b,)))
result
============================================
a == 12
a == 12
============================================
c == 45
b == 45
c == 45
b == 45
============================================
arguments == ('a', 1, 10)
arguments == ('a', 1, 10)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
y == 'a'
un == 1
There is no identifier assigned to 10 in the global namespace
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
un == 1
There is no identifier assigned to 10 in the global namespace
c == 45
b == 45