pythonlist

In Python, I want a list (or something) to pop its last member when I return from a function


This works, but is it the best way? Performance is not a concern. It just seems clunky and error-prone to do the pop manually.

I want to access all parts of the list in the called functions, but I don't want to know about them from the caller.

def outer():
    myList = ['outer']
    middle(myList)
    print("back to outer:", myList)
    
def middle(theList):
    theList.append('middle')
    inner(theList)
    print("back to middle:", theList)
    theList.pop()

def inner(expandedList):
    expandedList.append('inner')
    print("inner:", expandedList)
    expandedList.pop()
    
outer()


>>>
inner: ['outer', 'middle', 'inner']
back to middle: ['outer', 'middle']
back to outer: ['outer']
>>> 

If it helps to give context, I'm writing an XML to STL application. As I walk in, x/y/z positional shifts are cumulative as they are written out as absolute triangulated facet vertices, but when I return from a nested situation (the <container> element in my DTD), I no longer should incorporate the shift/offset of the inner element(s).

I've been programming since the 80s, but am relatively new to Python. Variable scope has been one of the more difficult aspects for me to come to terms with. I initially thought the meaning of the list would just naturally pop.

Editing my question to say @Guy has given a good answer.

Beyond that, if it's not going too far afield, I'd like to consider this alternate code sample:

def outer():
    myList = ['outer']
    myVal = 7
    print("outer myVal", myVal)
    middle(myList, myVal)
    print("back to outer:", myList)
    print("back to outer:", myVal)
    
def middle(theList, theVal):
    theList.append('middle')
    theVal += 4
    print("middle theVal", theVal)
    inner(theList, theVal)
    print("back to middle:", theList)
    print("back to middle:", theVal)
    #theList.pop()

def inner(expandedList, fiddledVal):
    expandedList.append('inner')
    fiddledVal = 47
    print("inner expandedList:", expandedList)
    print("inner fiddledVal:", fiddledVal)
    #expandedList.pop()
    
outer()

>>>
outer myVal 7
middle theVal 11
inner expandedList: ['outer', 'middle', 'inner']
inner fiddledVal: 47
back to middle: ['outer', 'middle', 'inner']
back to middle: 11
back to outer: ['outer', 'middle', 'inner']
back to outer: 7
>>> 

Simple integers, after returning from a called function, have the same values they had before their visit to the called function. Lists are modified by the called function in ways that persist after returning from it.

Short of reading all the Python documentation, is there something I could read to better understand the underlying distinction between the integer and the list?


Solution

  • There are more options, like working with local lists in the functions, but IMO the cleanest way is to just send a copy of the list to the next function

    def outer():
        lst = ['outer']
        middle(lst[:])
        print("back to outer:", lst)
    
    
    def middle(lst):
        lst.append('middle')
        inner(lst[:])
        print("back to middle:", lst)
    
    
    def inner(lst):
        lst.append('inner')
        print("inner:", lst[:])