PEP 558: Update for conversation with Guido
- new open questions around how storage and updates will work - note that we definitely *don't* want to return the write-through proxy from locals() at function scope
This commit is contained in:
parent
a6d74b181c
commit
94e6606edb
63
pep-0558.rst
63
pep-0558.rst
|
@ -125,6 +125,55 @@ function locals).
|
|||
Open Questions
|
||||
==============
|
||||
|
||||
Allowing local variable binding mutation outside trace functions
|
||||
----------------------------------------------------------------
|
||||
|
||||
This PEP allows local variable bindings to be mutated whenever code has access
|
||||
to the frame object - it doesn't restrict that ability to trace functions the
|
||||
way the status quo does.
|
||||
|
||||
It does this since it wants to allow trace functions to make changes, while
|
||||
removing the current bulk copy from ``f_locals`` back to the frame state when
|
||||
the trace function returns.
|
||||
|
||||
An alternative approach might be to *temporarily* replace ``f_locals`` with
|
||||
a write-through proxy while the trace function is running, and then swap it
|
||||
back to the result of ``locals()`` when the trace function returns.
|
||||
|
||||
|
||||
Where is the new ``locals()`` result stored?
|
||||
--------------------------------------------
|
||||
|
||||
If ``locals()`` is a new mapping distinct from the write-through proxy stored in
|
||||
``frame.f_locals``, where will that mapping be stored?
|
||||
|
||||
A new lazily initialised frame attribute seems like a plausible answer, but that
|
||||
raises new questions around how that attribute will be managed for module and
|
||||
class scopes (set to the same thing as ``f_locals``? Set to ``NULL``/``None``?)
|
||||
|
||||
Alternatively, it could be stored in ``f_locals`` most of the time (as it is
|
||||
today), and have the write-through proxy stored in a separate lazily
|
||||
initialised attribute that gets swapped in as ``f_locals`` only when calling
|
||||
trace functions.
|
||||
|
||||
|
||||
What happens with the default args for ``eval()`` and ``exec()``?
|
||||
-----------------------------------------------------------------
|
||||
|
||||
These are formally defined as inheriting ``globals()`` and ``locals()`` from
|
||||
the calling scope by default.
|
||||
|
||||
There doesn't seem to be any reason for the PEP to change this.
|
||||
|
||||
|
||||
Does mutating the ``f_locals`` proxy refresh the ``locals()`` mapping?
|
||||
----------------------------------------------------------------------
|
||||
|
||||
This is probably needed in order to retain the current behaviour where writes
|
||||
to ``frame.f_locals`` are immediately visible via references obtained via
|
||||
``locals()``.
|
||||
|
||||
|
||||
How much compatibility is enough compatibility?
|
||||
-----------------------------------------------
|
||||
|
||||
|
@ -227,6 +276,20 @@ This proposal deliberately *doesn't* formalise these semantics as is, since they
|
|||
only make sense in terms of the historical evolution of the language and the
|
||||
reference implementation, rather than being deliberately designed.
|
||||
|
||||
Rejected Alternatives
|
||||
=====================
|
||||
|
||||
Making ``locals()`` return the write-through proxy directly
|
||||
-----------------------------------------------------------
|
||||
|
||||
A number of changes have been made to ``locals()`` over the years to
|
||||
deliberately make it *harder* for arbitrary code to mutate function local
|
||||
variables without those changes being visible to the compiler at compile time.
|
||||
|
||||
As such the desired default semantics for ``locals()`` are those currently
|
||||
seen when a tracing function *isn't* installed, rather than the mutating
|
||||
behaviour currently seen when a tracing hook is installed.
|
||||
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
|
Loading…
Reference in New Issue