Search code examples
pythonfunctionnamespaces

In a Python function, Is there a way to tell the argument's variable name on the caller side?


I am trying to create a logger function:

def logger(someVariable): 
    # some code that prints the name of someVariable 

So when I call the function:

logger(myvarA)        # should output the string 'myvarA'
logger(someobj.varB)  # should output the string 'someobj.varB'
logger(myarr[3])      # should (probably) output 'myarr[3]'

Not sure if all or even any of these cases are possible? The use case for this is to have a simple function in iPython Notebook to log any variables for their values without having to type something like below:

logger(myVarA,'myVarA')
logger(myarr[i],'myarr[{}]'.format(i))

Solution

  • The inspect module (https://docs.python.org/3/library/inspect.html#inspect.getframeinfo) will also give you the code context. You simply need to parse that to get the text of what was passed. With only a single variable, it's pretty easy to do. Here's a sample.

    import inspect
    import re
    
    def handle_nested_parens(v):
       parens = 0
       output = ""
       for c in v:
           if c == ")":
               parens = parens - 1
               if parens < 0:
                   return output
           output += c
           if c == "(":
               parens = parens + 1
       return output
    
    def logger(v):
       currentframe = inspect.currentframe()
       code_context = inspect.getouterframes(currentframe,1)[1][4][0]
       variable = handle_nested_parens(re.sub(r".*logger\((.*)",r"\1", code_context))
       print("{0} => {1}".format(variable, v))
    
    
    def testing(a):
       return(a)
    
    def submain(a):
       ab = (1, 2, a)
       logger(testing(ab))
       return 15
    
    def main():
       xyz = "hello"
       logger(xyz)
       logger(submain(xyz))
    
    
    if __name__ == '__main__':
        a = 5
        logger(a)
        main()
    

    It outputs

    a => 5
    xyz => hello
    testing(ab) => (1, 2, 'hello')
    submain(xyz) => 15