Can an object inspect the name of the variable it's been assigned to?

前端 未结 7 1482

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):
           


        
相关标签:
7条回答
  • 2020-11-29 12:07

    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)

    0 讨论(0)
提交回复
热议问题