-3
def make_test_dice(*outcomes):
    """Return a die that cycles deterministically through OUTCOMES.

    >>> dice = make_test_dice(1, 2, 3)
    >>> dice()
    1
    >>> dice()
    2
    >>> dice()
    3
    >>> dice()
    1
    """
    assert len(outcomes) > 0, 'You must supply outcomes to make_test_dice'
    for o in outcomes:
        assert type(o) == int and o >= 1, 'Outcome is not a positive integer'
    index = len(outcomes) - 1
    print("Index1: ", index)
    def dice():
        nonlocal index 
        index = (index + 1) % len(outcomes)
        print("Index2: ", index)
        return outcomes[index]
    return dice

def main(): 
    foursided = make_test_dice(4,1,2)
    foursided()
    foursided()

if __name__ == "__main__": main()

So I realize that after calling make_test_dice, when calling foursided it skips the printing of the index1 var and goes to the dice function, as this is a closure. I understand that nonlocal variables refer to variables in the enclosing scope so that changing the var in the nested function would change it in the outer, but what I don't understand is how the variable of index is stored inside the nested function, because it needs a value index when setting the value in dice(). Given my print statements I believe it might be the previous value of index but I thought index would be gone after we exit the local frame of the make_test_dice function.

JamesMat
  • 7
  • 2
  • 3
    Don't duplicate questions please https://stackoverflow.com/questions/49729112/how-does-this-function-work-nested-functions, as I said read what `nonlocal` does https://stackoverflow.com/questions/1261875/python-nonlocal-statement – Chris_Rands Apr 09 '18 at 14:06
  • I did read what nonlocal does but it doesn't answer how the index variable is stored between function calls. i know nonlocal makes a variable in the outer function scope mutable in the inner scope without creating a new var of the same name, but that doesn't answer my main question. – JamesMat Apr 09 '18 at 14:10
  • You don't seem to understand `nonlocal` because that explains how `index` is updated, it's a bit like `global`. Try this, `x = 0` then `def f(): global x: x += 1`, then call `f()` several times and `print(x)` – Chris_Rands Apr 09 '18 at 14:14

1 Answers1

0

I realize that after calling make_test_dice, when calling foursided it skips the printing of the index1 var and goes to the dice function,

Nothing is skipped at all - foursided IS "the dice function". Or, more exactly, it's the function object that was created during the foursided = make_test_dice(4,1,2) call - each call to make_test_dice() creates a new "dice" function.

as this is a closure

Looks like you don't really understand what a closure is actually.

I understand that nonlocal variables refer to variables in the enclosing scope so that changing the var in the nested function would change it in the outer, but what I don't understand is how the variable of index is stored inside the nested function

Well, that's exactly what closure are all about: they do capture the environment they were defined in. In Python, functions being objects (instances of the builtin function class), they just use an instance attribute:

def show_closure(func):
    print(func.__closure__)
    for cell in func.__closure__:
        print(cell.cell_contents)


foursided = make_test_dice(4,1,2)
for i in range(4):
    show_closure(foursided)
    foursided()
bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118