[python] Convert Variable Name to String?

I would like to convert a python variable name into the string equivalent as shown. Any ideas how?

var = {}
print ???  # Would like to see 'var'
something_else = 3
print ???  # Would print 'something_else'

This question is related to python string variables

The answer is


I don't know it's right or not, but it worked for me

def varname(variable):
    names = []
    for name in list(globals().keys()):
        string = f'id({name})'
        if id(variable) == eval(string):
            names.append(name)
    return names[0]  

as long as it's a variable and not a second class, this here works for me:

def print_var_name(variable):
 for name in globals():
     if eval(name) == variable:
        print name
foo = 123
print_var_name(foo)
>>>foo

this happens for class members:

class xyz:
     def __init__(self):
         pass
member = xyz()
print_var_name(member)
>>>member

ans this for classes (as example):

abc = xyz
print_var_name(abc)
>>>abc
>>>xyz

So for classes it gives you the name AND the properteries


print "var"
print "something_else"

Or did you mean something_else?


This will work for simnple data types (str, int, float, list etc.)

>>> def my_print(var_str) : 
      print var_str+':', globals()[var_str]
>>> a = 5
>>> b = ['hello', ',world!']
>>> my_print('a')
a: 5
>>> my_print('b')
b: ['hello', ',world!']

By using the the unpacking operator:

>>> def tostr(**kwargs):
    return kwargs

>>> var = {}
>>> something_else = 3
>>> tostr(var = var,something_else=something_else)
{'var' = {},'something_else'=3}

You somehow have to refer to the variable you want to print the name of. So it would look like:

print varname(something_else)

There is no such function, but if there were it would be kind of pointless. You have to type out something_else, so you can as well just type quotes to the left and right of it to print the name as a string:

print "something_else"

To get the variable name of var as a string:

var = 1000
var_name = [k for k,v in locals().items() if v == var][0] 
print(var_name) # ---> outputs 'var'

Here is a succinct variation that lets you specify any directory. The issue with using directories to find anything is that multiple variables can have the same value. So this code returns a list of possible variables.

def varname( var, dir=locals()):
  return [ key for key, val in dir.items() if id( val) == id( var)]

I searched for this question because I wanted a Python program to print assignment statements for some of the variables in the program. For example, it might print "foo = 3, bar = 21, baz = 432". The print function would need the variable names in string form. I could have provided my code with the strings "foo","bar", and "baz", but that felt like repeating myself. After reading the previous answers, I developed the solution below.

The globals() function behaves like a dict with variable names (in the form of strings) as keys. I wanted to retrieve from globals() the key corresponding to the value of each variable. The method globals().items() returns a list of tuples; in each tuple the first item is the variable name (as a string) and the second is the variable value. My variablename() function searches through that list to find the variable name(s) that corresponds to the value of the variable whose name I need in string form.

The function itertools.ifilter() does the search by testing each tuple in the globals().items() list with the function lambda x: var is globals()[x[0]]. In that function x is the tuple being tested; x[0] is the variable name (as a string) and x[1] is the value. The lambda function tests whether the value of the tested variable is the same as the value of the variable passed to variablename(). In fact, by using the is operator, the lambda function tests whether the name of the tested variable is bound to the exact same object as the variable passed to variablename(). If so, the tuple passes the test and is returned by ifilter().

The itertools.ifilter() function actually returns an iterator which doesn't return any results until it is called properly. To get it called properly, I put it inside a list comprehension [tpl[0] for tpl ... globals().items())]. The list comprehension saves only the variable name tpl[0], ignoring the variable value. The list that is created contains one or more names (as strings) that are bound to the value of the variable passed to variablename().

In the uses of variablename() shown below, the desired string is returned as an element in a list. In many cases, it will be the only item in the list. If another variable name is assigned the same value, however, the list will be longer.

>>> def variablename(var):
...     import itertools
...     return [tpl[0] for tpl in 
...     itertools.ifilter(lambda x: var is x[1], globals().items())]
... 
>>> var = {}
>>> variablename(var)
['var']
>>> something_else = 3
>>> variablename(something_else)
['something_else']
>>> yet_another = 3
>>> variablename(something_else)
['yet_another', 'something_else']

I think this is a cool solution and I suppose the best you can get. But do you see any way to handle the ambigious results, your function may return? As "is" operator behaves unexpectedly with integers shows, low integers and strings of the same value get cached by python so that your variablename-function might priovide ambigous results with a high probability. In my case, I would like to create a decorator, that adds a new variable to a class by the varialbename i pass it:

def inject(klass, dependency):
klass.__dict__["__"+variablename(dependency)]=dependency

But if your method returns ambigous results, how can I know the name of the variable I added?

var any_var="myvarcontent"
var myvar="myvarcontent"
@inject(myvar)
class myclasss():
    def myclass_method(self):
        print self.__myvar    #I can not be sure, that this variable will be set...

Maybe if I will also check the local list I could at least remove the "dependency"-Variable from the list, but this will not be a reliable result.


Totally possible with the python-varname package (python3):

from varname import nameof

s = 'Hey!'

print (nameof(s))

Output:

s

Get the package here:

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


Technically the information is available to you, but as others have asked, how would you make use of it in a sensible way?

>>> x = 52
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', 
'x': 52, '__doc__': None, '__package__': None}

This shows that the variable name is present as a string in the globals() dictionary.

>>> globals().keys()[2]
'x'

In this case it happens to be the third key, but there's no reliable way to know where a given variable name will end up

>>> for k in globals().keys():
...   if not k.startswith("_"):
...     print k
...
x
>>>

You could filter out system variables like this, but you're still going to get all of your own items. Just running that code above created another variable "k" that changed the position of "x" in the dict.

But maybe this is a useful start for you. If you tell us what you want this capability for, more helpful information could possibly be given.


Does Django not do this when generating field names?

http://docs.djangoproject.com/en/dev//topics/db/models/#verbose-field-names

Seems reasonable to me.


I'd like to point out a use case for this that is not an anti-pattern, and there is no better way to do it.

This seems to be a missing feature in python.

There are a number of functions, like patch.object, that take the name of a method or property to be patched or accessed.

Consider this:

patch.object(obj, "method_name", new_reg)

This can potentially start "false succeeding" when you change the name of a method. IE: you can ship a bug, you thought you were testing.... simply because of a bad method name refactor.

Now consider: varname. This could be an efficient, built-in function. But for now it can work by iterating an object or the caller's frame:

Now your call can be:

patch.member(obj, obj.method_name, new_reg)

And the patch function can call:

varname(var, obj=obj)

This would: assert that the var is bound to the obj and return the name of the member. Or if the obj is not specified, use the callers stack frame to derive it, etc.

Could be made an efficient built in at some point, but here's a definition that works. I deliberately didn't support builtins, easy to add tho:

Feel free to stick this in a package called varname.py, and use it in your patch.object calls:

patch.object(obj, varname(obj, obj.method_name), new_reg)

Note: this was written for python 3.

import inspect

def _varname_dict(var, dct):
    key_name = None
    for key, val in dct.items():
        if val is var:
            if key_name is not None:
                raise NotImplementedError("Duplicate names not supported %s, %s" % (key_name, key))
            key_name = key
    return key_name

def _varname_obj(var, obj):
    key_name = None
    for key in dir(obj):
        val = getattr(obj, key)
        equal = val is var
        if equal:
            if key_name is not None:
                raise NotImplementedError("Duplicate names not supported %s, %s" % (key_name, key))
            key_name = key
    return key_name

def varname(var, obj=None):
    if obj is None:
        if hasattr(var, "__self__"):
            return var.__name__
        caller_frame = inspect.currentframe().f_back
        try:
            ret = _varname_dict(var, caller_frame.f_locals)
        except NameError:
            ret = _varname_dict(var, caller_frame.f_globals)
    else:
        ret = _varname_obj(var, obj)
    if ret is None:
        raise NameError("Name not found. (Note: builtins not supported)")
    return ret

This is not possible.

In Python, there really isn't any such thing as a "variable". What Python really has are "names" which can have objects bound to them. It makes no difference to the object what names, if any, it might be bound to. It might be bound to dozens of different names, or none.

Consider this example:

foo = 1
bar = 1
baz = 1

Now, suppose you have the integer object with value 1, and you want to work backwards and find its name. What would you print? Three different names have that object bound to them, and all are equally valid.

In Python, a name is a way to access an object, so there is no way to work with names directly. There might be some clever way to hack the Python bytecodes or something to get the value of the name, but that is at best a parlor trick.

If you know you want print foo to print "foo", you might as well just execute print "foo" in the first place.

EDIT: I have changed the wording slightly to make this more clear. Also, here is an even better example:

foo = 1
bar = foo
baz = foo

In practice, Python reuses the same object for integers with common values like 0 or 1, so the first example should bind the same object to all three names. But this example is crystal clear: the same object is bound to foo, bar, and baz.


It's not very Pythonesque but I was curious and found this solution. You need to duplicate the globals dictionary since its size will change as soon as you define a new variable.

def var_to_name(var):
    # noinspection PyTypeChecker
    dict_vars = dict(globals().items())

    var_string = None

    for name in dict_vars.keys():
        if dict_vars[name] is var:
            var_string = name
            break

    return var_string


if __name__ == "__main__":
    test = 3
    print(f"test = {test}")
    print(f"variable name: {var_to_name(test)}")

which returns:

test = 3
variable name: test

What are you trying to achieve? There is absolutely no reason to ever do what you describe, and there is likely a much better solution to the problem you're trying to solve..

The most obvious alternative to what you request is a dictionary. For example:

>>> my_data = {'var': 'something'}
>>> my_data['something_else'] = 'something'
>>> print my_data.keys()
['var', 'something_else']
>>> print my_data['var']
something

Mostly as a.. challenge, I implemented your desired output. Do not use this code, please!

#!/usr/bin/env python2.6
class NewLocals:
    """Please don't ever use this code.."""
    def __init__(self, initial_locals):
        self.prev_locals = list(initial_locals.keys())

    def show_new(self, new_locals):
        output = ", ".join(list(set(new_locals) - set(self.prev_locals)))
        self.prev_locals = list(new_locals.keys())
        return output
# Set up
eww = None
eww = NewLocals(locals())

# "Working" requested code

var = {}

print eww.show_new(locals())  # Outputs: var

something_else = 3
print eww.show_new(locals()) # Outputs: something_else

# Further testing

another_variable = 4
and_a_final_one = 5

print eww.show_new(locals()) # Outputs: another_variable, and_a_final_one

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to string

How to split a string in two and store it in a field String method cannot be found in a main class method Kotlin - How to correctly concatenate a String Replacing a character from a certain index Remove quotes from String in Python Detect whether a Python string is a number or a letter How does String substring work in Swift How does String.Index work in Swift swift 3.0 Data to String? How to parse JSON string in Typescript

Examples related to variables

When to create variables (memory management) How to print a Groovy variable in Jenkins? What does ${} (dollar sign and curly braces) mean in a string in Javascript? How to access global variables How to initialize a variable of date type in java? How to define a variable in a Dockerfile? Why does foo = filter(...) return a <filter object>, not a list? How can I pass variable to ansible playbook in the command line? How do I use this JavaScript variable in HTML? Static vs class functions/variables in Swift classes?