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:
parent
e47f9242f8
commit
91b9f68579
55
pep-0667.rst
55
pep-0667.rst
|
@ -278,6 +278,7 @@ They serve only to illustrate the proposed design.
|
||||||
return FrameLocalsProxy(self)
|
return FrameLocalsProxy(self)
|
||||||
|
|
||||||
class FrameLocalsProxy:
|
class FrameLocalsProxy:
|
||||||
|
"Implements collections.MutableMapping."
|
||||||
|
|
||||||
__slots__ "_frame"
|
__slots__ "_frame"
|
||||||
|
|
||||||
|
@ -332,24 +333,11 @@ They serve only to illustrate the proposed design.
|
||||||
continue
|
continue
|
||||||
yield name
|
yield name
|
||||||
|
|
||||||
def pop(self):
|
def __contains__(self, item):
|
||||||
f = self._frame
|
f = self._frame
|
||||||
co = f.f_code
|
if item in f._extra_locals:
|
||||||
if f._extra_locals:
|
return True
|
||||||
return f._extra_locals.pop()
|
return item in co._variable_names
|
||||||
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
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
f = self._frame
|
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()``
|
to make the semantics of ``locals()`` and ``frame.f_locals()``
|
||||||
intelligible, and their operation reliable.
|
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
|
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.
|
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
|
Open Issues
|
||||||
===========
|
===========
|
||||||
|
|
Loading…
Reference in New Issue