-2

I've always wondered if when you define a variable, you can somehow get the name you defined it with, and manipulate it as a string. I am trying to make some code more efficient in doing this.

I looked this up and didn't seem to hit the spot with what I found. I found some code that can retrieve the name of the class itself, but not the name of the created object.

class A:
    @classmethod
    def getname(cls):
        return cls.__name__

    def usename(self):
        return self.getname()

>> example = A()
>> print (example.usename())
A

I thought I would get a result looking like this:

example

It being literally the name of the object, not the class.

Is there a way of doing this? If there is, I would really appreciate it.

PS: if this question turns out to be a duplicate, sorry, would love it if ya'll point me to the answer :) and not delete this.

Dan
  • 160
  • 1
  • 6
  • 19

3 Answers3

1

What you think of as a "variable" is in Python nothing more than a reference to an object. See naming and binding in the Python documentation.

There is no 1:1 relation between objects and references. There can be more than one reference to an object. The CPython implementation even uses reference counting; an object will be de-allocated when there its reference count drops to 0.

The closest thing that an object has to a name is its "identity", which you can get by calling the id() function on the object. This is an integer which is unique during the lifetime of the object.

There is no universal way to get the the name of a reference/variable as a string.

If the name refers to an object that is subject to garbage collection, there is a roundabout way to get it (with thanks to Iain Shelvington for pointing it out in the comments):

import gc

test = [1, 2, 3]
rl = gc.get_referrers(test)
rd = {}
for j in rl:
    rd.update(j)

who = [k for k, v in rd.items() if v == test]
print(who)

This will print out ['test'].

Note that this does not apply to atomic objects like integers, strings and floats. It will only work for objects where gc.is_tracked(name) returns True.

Roland Smith
  • 42,427
  • 3
  • 64
  • 94
1

This isn't possible in Python. In theory the language could store down the first assignment name in some form, but it doesn't. Python also doesn't have anything like C#'s nameof() that could approximate this.

The main issue here is that the name is just a pointer to the object, you could have multiple names for the same thing (or none at the level you are working at - what would be the name of a value in a list, for example?), so which one would you expect to get?

example = A()
example2 = example
example = [A()]

Generally, if you want to do something like this, you want to use a data structure like a dictionary instead, that way you have access to the keys.

The best you could do is something where you forgo the manual assignment and construct the object using code that gives the object that name and assigns the variable dynamically. This would still have the issue that the name wouldn't match other references, and would be fragile code. Using a dictionary would be easier in that case.

You could also use __setattr__() to do something like this if you were assigning to a class attribute rather than a top-level variable. However, again, I'd argue a dictionary is the better option.

Gareth Latty
  • 86,389
  • 17
  • 178
  • 183
1

Actually there is a way to get names of the variables and attributes. You can get the list of all the names without namespace, and their values as a dictionary using the vars function.

>>>vars()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}

It printed all the predefined variables without a namespace. (built-in functions such as len and print have __ builtins __ namespace.).

But if you defined a variable:

>>>a = 2
>>>vars()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'a': 2}

Then you can find the a you defined. This also works for object. You'll get all the names of the object's namespace by calling vars with the object as an argument.

>>>class B:
    def __init__(self):
        self.x = "fruit"
        self.y = "anaconda"
        self.z = "flower pot"

>>>b = B()
>>>vars(b)
{'x': 'fruit', 'y': 'anaconda', 'z': 'flower pot'}

Using the vars function and dictionary handling you can achieve getting the object's variable name by the variable values, but there can be another value with identical values causing conflicts.

Summary: Using the vars built-in function and dictionary handling you can get the variable name of a value, but it has a chance to fail, when the values are not unique in the namespace.

Seb
  • 11
  • 2