[Python-Dev] PEP 558: Defined semantics for locals()

Nick Coghlan ncoghlan at gmail.com
Thu May 30 19:06:37 EDT 2019

On Fri., 31 May 2019, 5:20 am Xavier de Gaye, <xdegaye at gmail.com> wrote:

> Currently f_locals is documented as readonly [1].

Read-only in the sense that you can't rebind it to point to a different
object - the dict it points to is mutable.

> The PEP says:
> > * "Don't change what isn't broken": the current tracing mode problems
> are caused
> >   by a requirement that's specific to tracing mode (support for external
> >   rebinding of function local variable references), so it made sense to
> also
> >   restrict any related fixes to tracing mode
> >
> > However, actually attempting to implement and document that dynamic
> approach
> > highlighted the fact that it makes for a really subtle runtime state
> dependent
> > behaviour distinction in how ``frame.f_locals`` works, and creates
> several
> > new edge cases around how ``f_locals`` behaves as trace functions are
> added
> > and removed.
> >
> > Accordingly, the design was switched to the current one, where
> > ``frame.f_locals`` is always a write-through proxy, and ``locals()`` is
> always
> > a dynamic snapshot, which is both simpler to implement and easier to
> explain.
> Do these edge cases still exist when f_locals write access is restricted
> to code executed by the tracing function (which is more restrictive than
> 'tracing mode') ?

We can use the condition frame->f_trace not NULL and tstate->tracing true
> (tstate being a pointer to the PyThreadState structure) to know when code
> is executed by the tracing function [2]:
> * The condition on tstate->tracing allows to figure out if we are running
> a frame executed by the trace function as opposed to a frame that is being
> traced or a frame executed in 'regular operation'.
> * The condition on frame->f_trace removes the ambiguity whether
> tstate->tracing is set by a tracing function or by a profiling function.

Always creating the proxy and sometimes bypassing it and returning the
snapshot instead would indeed have fewer edge cases than sometimes storing
the snapshot directly on the frame object without creating the proxy at all.

It's still significantly harder to document than "frame.f_locals references
a proxy, locals() creates a snapshot", though.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20190531/9e2644e4/attachment.html>

More information about the Python-Dev mailing list