In Python, is there a way for an instance of an object to see the variable name it\'s assigned to? Take the following for example:
class MyObject(object):
It can't be ordinarily done, though this can be achieved by using introspection and facilities meant for debugging a program. The code must run from a ".py" file though, and not from just compiled bytecode, or inside a zipped module - as it relies on the reading of the file source code, from within the method that should find about "where it is running".
The trick is to access the execution frame where the object was initialized from - with inspect.currentframe - the frame object has a "f_lineno" value which states the line number where the call to the object method (in this case, __init__
) has been called. The function inspect.filename allows one to retrieve the source code for the file, and fetch the apropriate line number.
A naive parse then peek the part preeceding an "=" sign, and assumes it is the variable that will contain the object.
from inspect import currentframe, getfile
class A(object):
def __init__(self):
f = currentframe(1)
filename = getfile(f)
code_line = open(filename).readlines()[f.f_lineno - 1]
assigned_variable = code_line.split("=")[0].strip()
print assigned_variable
my_name = A()
other_name = A()
That won't work for multiple assignents, expressions composing with the object before the assignemtn is made, objects being appended to lists or added to dictionaries or sets, object instantiation in intialization of for
loops, and God knows which more situations --
And have in mind that after the first attribution, the object could be referenced by any other variable as well.
Botton line: it is possible, but as a toy - it can't be used i production code -
just have the varibal name to be passed as a string during object initialization, just as one has to do when creating a collections.namedtuple
The "right way" to do it, if you are needing the name, is to explicitly pass the name to the object initialization, as a string parameter, like in:
class A(object):
def __init__(self, name):
self.name = name
x = A("x")
And still, if absolutely need to type the objects'name only once, there is another way - read on. Due to Python's syntax, some special assignments, not using the "=" operator do allow an object to know it is assigned name. So, other statemtns that perform assignents in Python are the for, with, def and class keywords - It is possible to abuse this, as specfically a class creation and a function definition are assignment statements that create objects which "know" their names.
Let's focus on the def
statement. It ordinarily creates a function. But using a decorator you can use "def" to create any kind of object - and have the name used for the function available to the constructor:
class MyObject(object):
def __new__(cls, func):
# Calls the superclass constructor and actually instantiates the object:
self = object.__new__(cls)
#retrieve the function name:
self.name = func.func_name
#returns an instance of this class, instead of a decorated function:
return self
def __init__(self, func):
print "My name is ", self.name
#and the catch is that you can't use "=" to create this object, you have to do:
@MyObject
def my_name(): pass
(This last way of doing it could be used in production code, unlike the one which resorts to reading the source file)