On Nov 15, 1:36 pm, Terry Reedy <tjre...@udel.edu> wrote: > Peter Otten wrote: > > Mike wrote: > > >> I'll apologize first for this somewhat lengthy example. It does > >> however recreate the problem I've run into. This is stripped-down code > >> from a much more meaningful system. > > >> I have two example classes, "AutoChecker" and "Snapshot" that evaluate > >> variables in their caller's namespace using the frame stack. As > >> written, the output is not what is expected: the variables evaluate to > >> "stagnant" values. > > >> However, if the one indicated line is uncommented, then the result is > >> as expected. > > >> So my questions are: Is this a bug in Python? > > No. The existence and use of sys._getframe -- notice the leading > underscore -- is a CPython implementation artifact. Use at your own risk. > > >> Is this an invalid use of frame data? > > Up to you to decide. > > >> Why does the single line "sys._getframe(1).f_locals" > > >> fix the behavior? > > It updates the dictionary. > > > > > A simplified demonstration of your problem: > > >>>> def f(update): > > ... a = locals() > > ... x = 42 > > ... if update: locals() > > ... print a > > ... > >>>> f(False) > > {'update': False} > >>>> f(True) > > {'a': {...}, 'x': 42, 'update': True} > > > The local namespace is not a dictionary, and the locals()/f_locals > > dictionary contains a snapshot of the local namespace. Accessing the > > f_locals attribute is one way to trigger an update of that snapshot. > > > What's puzzling is that the same dictionary is reused. > > Efficiency? Consistency? The doc for locals says "locals() > Update and return a dictionary representing the current local symbol > table." In class statements, where (currently) the local namespace *is* > a dict, no update is needed and locals() simply returns the dict, the > same one each time. > > Terry Jan Reedy
Thanks for the replies. If Peter's concise and much-appreciated example were to be modified as such: >>> def f(update): .....: a = inspect.stack()[0][0].f_locals .....: x = 42 .....: if update: .....: inspect.stack()[0][0].f_locals .....: print a .....: >>> f(False) {'update': False} >>> f(True) {'a': {...}, 'x': 42, 'update': True} Now there's no use of locals() to perform its documented "Update", but just a simple access of a dictionary. This behavior is curious. Further modification by accessing 'a' instead of '...f_locals' upon update produces: >>> f(False) {'update': False} >>> f(True) {'update': True} Checking the id() of 'a' and '...f_locals' shows the same "address". How is it that '...f_locals' gets updated in this example? Is it done in "stack()"? Where exactly is the frame data stored prior to updating the dictionary and can I get to it? Thanks, Mike -- http://mail.python.org/mailman/listinfo/python-list