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?
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:
- http://groups.google.com/group/comp.lang.python/msg/237dc92f3629dd9a?pli=1
- http://aspn.activestate.com/ASPN/Mail/Message/python-Tutor/330294
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.
a = 1; b = a
. What is the name of 1
? –
Tobacco 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*?"
To add to @Jay's answer, some concepts...
Python's "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)
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.
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.
ANAME=1
, and you want to print that as "The Name is: ANAME"
? –
Forward varnameis(1)
should do. –
Andel BNAME=1
so it's not uniqe. Just as you demonstrated above. Thus I was forced to compare this to an array of acceptable names. –
Forward YES
import inspect
def printVariableName(abc):
newvar=inspect.stack()[1][4][0]
print(newvar.split("(")[1].split(")")[0])
noob=10
printVariableName(noob)
Output:
noob
li = [printVariableName(arg) for arg in [arg1, arg2]
, I get arg
and arg
, not arg1
and arg2
. Is there a way to do that? –
Waffle 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
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.
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.
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.
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:
-
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__
-
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 - You may want to print the __dict__ of the class of your enums.
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.
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.
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'
The f-string can do this:
def log(obj):
print(f"{obj=})
x = 5
log(x)
>>> x=5
© 2022 - 2024 — McMap. All rights reserved.
=
as inprint(f"{foo=} {bar=}")
that prints both variable names and values, I explained it further at: #32001434 – Phonation