The Python Oracle

Getting the name of a variable as a string

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Romantic Lands Beckon

--

Chapters
00:00 Getting The Name Of A Variable As A String
00:41 Answer 1 Score 140
01:32 Answer 2 Score 182
02:37 Answer 3 Score 55
03:02 Answer 4 Score 288
03:27 Thank you

--

Full question
https://stackoverflow.com/questions/1842...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #variables

#avk47



ANSWER 1

Score 288


With Python 3.8 one can simply use f-string debugging feature:

>>> foo = dict()
>>> f'{foo=}'.split('=')[0]
'foo' 

One drawback of this method is that in order to get 'foo' printed you have to add f'{foo=}' yourself. In other words, you already have to know the name of the variable. In other words, the above code snippet is exactly the same as just

>>> 'foo'



ANSWER 2

Score 182


Even if variable values don't point back to the name, you have access to the list of every assigned variable and its value, so I'm astounded that only one person suggested looping through there to look for your var name.

Someone mentioned on that answer that you might have to walk the stack and check everyone's locals and globals to find foo, but if foo is assigned in the scope where you're calling this retrieve_name function, you can use inspect's currentframe to get you all of those local variables.

My explanation might be a little bit too wordy (maybe I should've used a "foo" less words), but here's how it would look in code (Note that if there is more than one variable assigned to the same value, you will get both of those variable names):

import inspect

x, y, z = 1, 2, 3

def retrieve_name(var):
    callers_local_vars = inspect.currentframe().f_back.f_locals.items()
    return [var_name for var_name, var_val in callers_local_vars if var_val is var]

print(retrieve_name(y))

If you're calling this function from another function, something like:

def foo(bar):
    return retrieve_name(bar)

foo(baz)

And you want the baz instead of bar, you'll just need to go back a scope further. This can be done by adding an extra .f_back in the caller_local_vars initialization.

See an example here: ideone




ANSWER 3

Score 140


The only objects in Python that have canonical names are modules, functions, and classes, and of course there is no guarantee that this canonical name has any meaning in any namespace after the function or class has been defined or the module imported. These names can also be modified after the objects are created so they may not always be particularly trustworthy.

What you want to do is not possible without recursively walking the tree of named objects (or at least iterating the list of names in the containing scope as in @scohe001's answer); a name is a one-way reference to an object. A common or garden-variety Python object contains no references to its names. Imagine if every integer, every dict, every list, every Boolean needed to maintain a list of strings that represented names that referred to it! It would be an implementation nightmare, with little benefit to the programmer.




ANSWER 4

Score 55


On python3, this function will get the outer most name in the stack:

import inspect


def retrieve_name(var):
    """
    Gets the name of var. Does it from the out most frame inner-wards.
    :param var: variable to get name from.
    :return: string
    """
    for fi in reversed(inspect.stack()):
        names = [var_name for var_name, var_val in fi.frame.f_locals.items() if var_val is var]
        if len(names) > 0:
            return names[0]

It is useful anywhere on the code. Traverses the reversed stack looking for the first match.