@@ -832,45 +832,67 @@ def f():
832832 # k2, x = k1(None) # multi-shotting from earlier resume point
833833 # test[x == "cont 2 first time"]
834834
835- # If you need to scope like `nonlocal`, use the classic solution: box the value
836- # to avoid the need to overwrite the name.
835+ # If you need to scope like `nonlocal`, use the classic solution: box the value,
836+ # so you have no need to overwrite the name; you can replace the thing in the box .
837837 #
838838 # (Classic from before `nonlocal` declarations were a thing. They were added in 3.0;
839839 # for historical interest, see https://www.python.org/dev/peps/pep-3104/ )
840840 with testset ("scoping, using a box" ):
841- # TODO: better example
842841 with continuations :
843- def f ():
844- # original function scope
845- x = box (None )
842+ # poor man's execution trace
843+ def make_tracing_box_updater (thebox , trace ):
844+ def update (value ):
845+ trace .append (f"old: { unbox (thebox )} " )
846+ thebox << value
847+ trace .append (f"new: { unbox (thebox )} " )
848+ return value
849+ return update
850+
851+ # If we wanted to replace the list instance later, we could pass the list in a box, too.
852+ def f (lst ):
853+ # Now there is just one `x`, which is the box; we just update the contents.
854+ # Original function scope
855+ x = box ("f" )
856+ lst .append (f"initial: { unbox (x )} " )
857+ update = make_tracing_box_updater (x , lst )
846858
847- # continuation 1 scope begins here
859+ # Continuation 1 scope begins here
848860 # (from the statement following `call_cc` onward, but including the `k1`)
849861 k1 = call_cc [get_cc ()]
850862 if iscontinuation (k1 ):
851- # Now there is just one `x`, which is the box; we just update the contents.
852- x << "cont 1 first time"
853- return k1 , unbox (x )
863+ return k1 , update ("k1 first" )
864+ update ("k1 again" )
854865
855- # continuation 2 scope begins here
866+ # Continuation 2 scope begins here
856867 k2 = call_cc [get_cc ()]
857868 if iscontinuation (k2 ):
858- x << "cont 2 first time"
859- return k2 , unbox ( x )
869+ return k2 , update ( "k2 first" )
870+ update ( "k2 again" )
860871
861- x << "cont 2 second time"
862872 return None , unbox (x )
863873
864- k1 , x = f ()
865- test [x == "cont 1 first time" ]
874+ trace = []
875+ k1 , x = f (trace )
876+ test [x == "k1 first" ]
877+ test [trace == ['initial: f' , 'old: f' , 'new: k1 first' ]]
866878 k2 , x = k1 (None ) # when resuming, send `None` as the new value of variable `k1` in continuation 1
867- test [x == "cont 2 first time" ]
879+ test [x == "k2 first" ]
880+ test [trace == ['initial: f' , 'old: f' , 'new: k1 first' ,
881+ 'old: k1 first' , 'new: k1 again' , 'old: k1 again' , 'new: k2 first' ]]
868882 k3 , x = k2 (None )
869883 test [k3 is None ]
870- test [x == "cont 2 second time" ]
884+ test [x == "k2 again" ]
885+ test [trace == ['initial: f' , 'old: f' , 'new: k1 first' ,
886+ 'old: k1 first' , 'new: k1 again' , 'old: k1 again' , 'new: k2 first' ,
887+ 'old: k2 first' , 'new: k2 again' ]]
871888
872889 k2 , x = k1 (None ) # multi-shotting from earlier resume point
873- test [x == "cont 2 first time" ]
890+ test [x == "k2 first" ]
891+ test [trace == ['initial: f' , 'old: f' , 'new: k1 first' ,
892+ 'old: k1 first' , 'new: k1 again' , 'old: k1 again' , 'new: k2 first' ,
893+ 'old: k2 first' , 'new: k2 again' ,
894+ 'old: k2 again' , 'new: k1 again' , 'old: k1 again' , 'new: k2 first' ]]
895+ # ^^^^^^^^^^^^^^^ state as left by `k2` before the multi-shot
874896
875897if __name__ == '__main__' : # pragma: no cover
876898 with session (__file__ ):
0 commit comments