PEP 667: Update to account for changes to PEP 558 and feedback from Nick. (#2180)

* Remove incorrect implementation of pop(). There is an implementation in collections.MutableMapping so it is not needed. Add implementation of __contains__.

* Remove outdated section on differences with PEP 558.
This commit is contained in:
Mark Shannon 2021-12-06 10:11:27 +00:00 committed by GitHub
parent e47f9242f8
commit 91b9f68579
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 8 additions and 47 deletions

View File

@ -278,6 +278,7 @@ They serve only to illustrate the proposed design.
return FrameLocalsProxy(self)
class FrameLocalsProxy:
"Implements collections.MutableMapping."
__slots__ "_frame"
@ -332,24 +333,11 @@ They serve only to illustrate the proposed design.
continue
yield name
def pop(self):
def __contains__(self, item):
f = self._frame
co = f.f_code
if f._extra_locals:
return f._extra_locals.pop()
for index, _ in enumerate(co._variable_names):
val = f._locals[index]
if val is NULL:
continue
if index in co._cells:
cell = val
val = cell.cell_contents
if val is NULL:
continue
cell.cell_contents = NULL
else:
f._locals[index] = NULL
return val
if item in f._extra_locals:
return True
return item in co._variable_names
def __len__(self):
f = self._frame
@ -387,41 +375,14 @@ This PEP and PEP 558 [2]_ share a common goal:
to make the semantics of ``locals()`` and ``frame.f_locals()``
intelligible, and their operation reliable.
In the author's opinion, PEP 558 fails to do that as it is too
complex, and has many corner cases which will lead to bugs.
The key difference between this PEP and PEP 558 is that
PEP 558 requires an internal copy of the local variables,
PEP 558 keeps an internal copy of the local variables,
whereas this PEP does not.
Maintaining a copy adds considerably to the complexity of both
the specification and implementation, and brings no real benefits.
The semantics of ``frame.f_locals``
-----------------------------------
PEP 558 does not specify exactly when the internal copy is
updated, making the behavior of PEP 558 impossible to reason about.
In this PEP, ``frame.f_locals`` is a view onto the underlying frame.
It is always synchronized with the underlying frame.
In PEP 558, there is an additional copy of the local variables present
in the frame which is updated whenever ``frame.f_locals`` is accessed.
PEP 558 does not make it clear whether calls to ``locals()``
update ``frame.f_locals`` or not.
For example consider::
def foo():
x = sys._getframe().f_locals
y = locals()
print(tuple(x))
print(tuple(y))
It is not clear from PEP 558 (at time of writing) what would be printed.
Does the call to ``locals()`` update ``x``?
Would ``"y"`` be present in either ``x`` or ``y``?
With this PEP it should be clear that the above would print::
('x', 'y')
('x',)
Open Issues
===========