How to print original variable's name in Python after it was returned from a function?

PythonVariables

Python Problem Overview


I have enum and use the variables like myEnum.SomeNameA, myEnum.SomeNameB, etc. When I return one of these variables from a function, can I print their names (such as myEnum.SomeNameA) instead of the value they returned?

Python Solutions


Solution 1 - Python

Short answer: no.

Long answer: this is possible with some ugly hacks using traceback, inspect and the like, but it's generally probably not recommended for production code. For example see:

Perhaps you can use a workaround to translate the value back to a name/representational string. If you post some more sample code and details about what you're wanting this for maybe we can provide more in-depth assistance.

Solution 2 - Python

There is no such thing as a unique or original variable name http://www.amk.ca/quotations/python-quotes/page-8

>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! > >Fredrik Lundh, 3 Nov 2000, in answer to the question "How can I get the name of a variable from C++ when I have the PyObject?"*

Solution 3 - Python

To add to @Jay's answer, some concepts...

Python "variables" are simply references to values. Each value occupies a given memory location (see id())

>>> id(1)
10052552

>>> sys.getrefcount(1)
569

From the above, you may notice that the value "1" is present at the memory location 10052552. It is referred to 569 times in this instance of the interpreter.

>>> MYVAR = 1
>>> sys.getrefcount(1)
570

Now, see that because yet another name is bound to this value, the reference count went up by one.

Based on these facts, it is not realistic/possible to tell what single variable name is pointing to a value.

I think the best way to address your issue is to add a mapping and function to your enum reference back to a string name.

myEnum.get_name(myEnum.SomeNameA) 

Please comment if you would like sample code.

Solution 4 - Python

Yes.

In your case with enums, it's easy:

>>> from enum import Enum
>>> class Type(Enum):
...   AB, SBS, INTERLACED, SPLIT = range(4)
...
>>> Type.AB
<Type.AB: 0>
>>> print(Type.AB)
Type.AB
>>> Type.AB.name
'AB'
>>> Type.AB.value
0
>>> Type(0)
<Type.AB: 0>

In general, it could be ambiguous:

>>> def varname(v): d = globals(); return [k for k in d if d[k] == v]
...
>>> def varnameis(v): d = globals(); return [k for k in d if d[k] is v]
...
>>> foo = {'a':'aap'}
>>> bar = {'a':'aap'}
>>> varname(foo)
['foo', 'bar']
>>> varnameis(foo)
['foo']

Or even misleading:

>>> foo = "A"; bar = "A"
>>> varnameis("A")
['foo', 'bar']
>>> foo = "An immutable value."; bar = "An immutable value."
>>> varnameis("An immutable value.")
[]
>>> foo = "An immutable value."; bar = "An immutable value."; varnameis("An immutable value.")
['foo', 'bar']
>>> import sys; sys.version
'3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 02:47:15) [MSC v.1900 32 bit (Intel)]'

To search in any scope, use this:

>>> def varname(v, scope=None): d = globals() if not scope else vars(scope); return [k for k in d if d[k] == v]
...
>>> import time
>>> time.timezone
-3600
>>> varname(-3600)
[]
>>> varname(-3600, time)
['timezone']

To avoid ambiguity, wrap your name with the data.

Solution 5 - Python

Python 3.8 added a new and probably a LITTLE better solution to this:

my_nice_variable_name = 'test'
print(f'{my_nice_variable_name=}')

# Output:
# my_nice_variable_name='test'

Here you could work with the string output. Still not advisable but maybe a little better than other ways of doing it.

Solution 6 - Python

Just use the text you want to print as the value of the enum, as in

class MyEnum (object):
    valueA = "valueA"
    valueB = "valueB"

comparing strings for identity is almost as efficient in Python as is comparing integer values (this is due to the fact the strings are immutable as have a hash value)

Of course there are easier ways to create the enum in the first place:

class Enum (object):
    def __init__(self, *values):
        for v in values:
            self.__dict__[v] = v

Then, create you enumeration like this:

MyEnum = Enum("valueA", "valueB")

ans access the same way as above:

MyEnum.valueA

Solution 7 - Python

There are two answers to this question: Yes and No.

Can you do it?  -- Yes (in most cases)
Is it worth it? -- No  (in most cases)

How to do it:

It depends on an implementation of enums. For example:

class Enum:
    A = 1
    B = 2

It doesn't matter whether there are 100 names refers to an integer whose name you'd like to find if you know enums class object and all they're names (or at least a unique prefix) in that class.

For the example above as @batbrat suggested you can inspect 'Enum.__dict__' using namestr():

 >>> getEnum = lambda: Enum.A
 >>> namestr(getEnum(), Enum.__dict__)
 >>> ['A']

In this case you even don't have to know all enum names. If enums implemented differently then you might need to use a different hack. There will be some solution in most cases e.g., see @Jay's answer. But it doesn't matter because..

Is it worth it?
  • Some enum implementations may require ugly, complex and in the end unreliable hacks to implement namestr().

  • Enum class can return answer by itself (see @David's, @Ber's, @gahooa's answers).

  • As @Ber pointed out there is no builtin Enum and switch statement in Python (see PEP-0275, PEP-3103). It is worth investigating solutions without enums.

Solution 8 - Python

YES

import inspect
        
def printVariableName(abc):
    newvar=inspect.stack()[1][4][0]
    print(newvar.split("(")[1].split(")")[0])

noob=10
printVariableName(noob)

Output:

noob

Solution 9 - Python

You could store the canonical name as an attribute of the instance, and then assign it to a variable with the same name. This might work:

class MyEnum(object):
    def __new__(cls, name):
        try:
            return getattr(MyEnum, name)
        except AttributeError:
            e = super(MyEnum, cls).__new__(cls)
            e.name = name
            setattr(MyEnum, name, e)
            return e

Regardless, it's not a particularly "Pythonic" thing to do.

Solution 10 - Python

On second thought:

Since Python does not provide native Enum types, you should not ask for one, but instead use other, more powerful construct to build your program. Otherwise, the next step will invariably be "Why does Python not have a switch ...: statement, and how do I best emulate it?"

Since Enums are often used to define some kind of state, a much better approach is this: Create a base class that define all the abstract properties, attributes and methods belonging to a state. Then, for each state, derive a sub class that implements the specific behavior of this state. You can then pass around these classes (or maybe instances thereof) to handle the state and its behaviour.

If you use classes instead of instances (the Python way of a "singleton"), you can simply check for any given state (not that it should be necessary) by if current_state is StateA: (note the is instead of ==) with no performance penalty over comparing integer values.

And of course, you can define a name attribute and a __str__() method to access and print the state's name.

Solution 11 - Python

As far as I know, that will require some introspection. You can try using the inspect module.

There are a few simple things you may want to try before that:

  1. This is not the exact code that should be used. You will have to retrieve the variable name from dict before printing.
    print myEnum.dict
    
  2. If you want to print the variable name from inside the function, you can try the functions - vars(), locals() and globals().
    Edit:
    I just noticed that this is not what you want. In that case adding a dict and a function may work
  3. <li>
        You may want to print the __dict__ of the class of your enums.
    </li>
    

All that said, there aren't standard enumerations in Python. It would help to know how you are creating them.

On second thoughts, you can maintain your variables as a dictionary in the enum, keyed by variable name and provide a method of the enumeration to find the right variable and print its name. This solution (keeping a dict) is bad because variable values aren't necessarily unique.

Edit:
The problem is not trivial, so you may want to use a tried and tested solution. IMHO, you would be better off avoiding the situation if you can.

Solution 12 - Python

Erlang has a concept called "atoms" -- they are similar to string constants or enumerations. Consider using a string constant as the value of your enum -- the same as the name of the enum.

Solution 13 - Python

I know it's a an old question but it's possible using f strings.

my_variable = some_object
f'{my_variable=}'.split('=', 1)[0]

this would print 'my_variable'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser34537View Question on Stackoverflow
Solution 1 - PythonJayView Answer on Stackoverflow
Solution 2 - PythonJohan BuretView Answer on Stackoverflow
Solution 3 - PythongahooaView Answer on Stackoverflow
Solution 4 - PythonCees TimmermanView Answer on Stackoverflow
Solution 5 - PythonKevin MüllerView Answer on Stackoverflow
Solution 6 - PythonBerView Answer on Stackoverflow
Solution 7 - PythonjfsView Answer on Stackoverflow
Solution 8 - PythonProNoobView Answer on Stackoverflow
Solution 9 - PythonDavid ZView Answer on Stackoverflow
Solution 10 - PythonBerView Answer on Stackoverflow
Solution 11 - PythonbatbratView Answer on Stackoverflow
Solution 12 - PythongahooaView Answer on Stackoverflow
Solution 13 - Pythongioxc88View Answer on Stackoverflow