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)
|
||||
|
||||
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
|
||||
===========
|
||||
|
|
Loading…
Reference in New Issue