Getting the name of a variable as a string

Posted on

Solving problem is about exposing yourself to as many situations as possible like Getting the name of a variable as a string and practice these strategies over and over. With time, it becomes second nature and a natural way you approach any problems in general. Big or small, always start with a plan, use other strategies mentioned here till you are confident and ready to code the solution.
In this post, my aim is to share an overview the topic about Getting the name of a variable as a string, which can be followed any time. Take easy to follow this discuss.

Getting the name of a variable as a string

This thread discusses how to get the name of a function as a string in Python:
How to get a function name as a string?

How can I do the same for a variable? As opposed to functions, Python variables do not have the __name__ attribute.

In other words, if I have a variable such as:

foo = dict()
foo['bar'] = 2

I am looking for a function/attribute, e.g. retrieve_name() in order to create a DataFrame in Pandas from this list, where the column names are given by the names of the actual dictionaries:

# List of dictionaries for my DataFrame
list_of_dicts = [n_jobs, users, queues, priorities]
columns = [retrieve_name(d) for d in list_of_dicts]

Answer #1:

Using the python-varname package, you can easily retrieve the name of the variables

https://github.com/pwwang/python-varname

As of v0.6.0, in your case, you can do:

from varname.helpers import Wrapper
foo = Wrapper(dict())
# foo.name == 'foo'
# foo.value == {}
foo.value['bar'] = 2

For list comprehension part, you can do:

n_jobs = Wrapper(<original_value>)
users = Wrapper(<original_value>)
queues = Wrapper(<original_value>)
priorities = Wrapper(<original_value>)
list_of_dicts = [n_jobs, users, queues, priorities]
columns = [d.name for d in list_of_dicts]
# ['n_jobs', 'users', 'queues', 'priorities']
# REMEMBER that you have to access the <original_value> by d.value

You can also try to retrieve the variable name DIRECTLY:

from varname import nameof
foo = dict()
fooname = nameof(foo)
# fooname == 'foo'

Note that this is working in this case as you expected:

n_jobs = <original_value>
d = n_jobs
nameof(d) # will return d, instead of n_jobs
# nameof only works directly with the variable

I am the author of this package. Please let me know if you have any questions or you can submit issues on Github.

Answered By: Panwen Wang

Answer #2:

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; 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.

Answered By: kindall

Answer #3:

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 current frame 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

Answered By: scohe001

Answer #4:

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

>>> foo = dict()
>>> f'{foo=}'.split('=')[0]
'foo'
Answered By: Aivar Paalberg

Answer #5:

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.

Answered By: juan Isaza

Answer #6:

I don’t believe this is possible. Consider the following example:

>>> a = []
>>> b = a
>>> id(a)
140031712435664
>>> id(b)
140031712435664

The a and b point to the same object, but the object can’t know what variables point to it.

Answered By: korylprince

Answer #7:

def name(**variables):
    return [x for x in variables]

It’s used like this:

name(variable=variable)
Answered By: fdvfcges

Answer #8:

I wrote the package sorcery to do this kind of magic robustly. You can write:

from sorcery import dict_of
columns = dict_of(n_jobs, users, queues, priorities)

and pass that to the dataframe constructor. It’s equivalent to:

columns = dict(n_jobs=n_jobs, users=users, queues=queues, priorities=priorities)
Answered By: Alex Hall

Leave a Reply

Your email address will not be published. Required fields are marked *