# PEP 667 -- Consistent views of namespaces

**URL:** <https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631>\
**Category:** PEPs\
**Created:** [February 22, 2024, 11:39am UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631 "2024-02-22T11:39:37Z")\
**Posts on this page:** 18\
**Page:** 2

<div class="post-metadata">

**Author:** ![markshannon](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/markshannon/32/72_2.png) [@markshannon](https://discuss.python.org/u/markshannon)\
**Post date:** [April 24, 2024, 11:46am UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/21 "2024-04-24T11:46:52Z")

</div>

I really don’t see how that changes whether `locals()` is well defined.  
Even if `sys._getframe` is not implemented, the semantics is clear.

---

<div class="post-metadata">

**Author:** ![ncoghlan](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ncoghlan/32/14266_2.png) [@ncoghlan](https://discuss.python.org/u/ncoghlan)\
**Post date:** [April 24, 2024, 2:10pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/22 "2024-04-24T14:10:38Z")

</div>

It’s clear given CPython’s frame API semantics, hence it being fine for 667’s purposes (fixing the behavioural issues in CPython)

It isn’t enough for the goal of PEP 558, which is to replace the “mutating the result of locals() has undefined behaviour” text in the function’s written specification with the actual expected semantics (as 667 is implementing them) written in a way that makes sense to a reader that may not even know that the frame API exists.

This is getting off-topic for this thread though: whether 558 is Withdrawn in favour of 667 or revised to depend on 667 instead of being an alternative to it, the update reflects agreement that 667 is a desirable change. Since 667 _isn’t_ proposing to document the updated locals() semantics, the question of exactly how to do so isn’t a topic the PEP needs to address.

---

<div class="post-metadata">

**Author:** ![guido](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/guido/32/21_2.png) [@guido](https://discuss.python.org/u/guido)\
**Post date:** [April 24, 2024, 3:24pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/23 "2024-04-24T15:24:37Z")

</div>

This is just about updating the docs for `locals()`. Just propose appropriate words in a PR once the implementation has landed (or as part of the implementation). No separate PEP is needed, nor does PEP 667 have to specify the documentation.

---

<div class="post-metadata">

**Author:** ![ncoghlan](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ncoghlan/32/14266_2.png) [@ncoghlan](https://discuss.python.org/u/ncoghlan)\
**Post date:** [April 25, 2024, 4:45am UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/24 "2024-04-25T04:45:48Z")

</div>

> [@guido](#):
>
> Just propose appropriate words in a PR once the implementation has landed (or as part of the implementation). No separate PEP is needed, nor does PEP 667 have to specify the documentation.

That seems like a good way forward to me, so I posted a DO-NOT-MERGE PR (with the proposed wording from PEP 558) that can have the merge blocking label removed once the PEP 667 implementation has been merged: [locals() documentation update for PEP 667 by ncoghlan · Pull Request #118265 · python/cpython · GitHub](https://github.com/python/cpython/pull/118265)

---

<div class="post-metadata">

**Author:** ![gpshead](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gpshead/32/54_2.png) [@gpshead](https://discuss.python.org/u/gpshead)\
**Post date:** [April 25, 2024, 10:08pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/25 "2024-04-25T22:08:31Z")

</div>

The Python Steering Council is happy to accept “PEP 667 - Consistent views of namespaces” - **under the condition that the PEP text be updated to take out just the planned “to be removed in” dates for the newly deprecated APIs** as part of making your PR to mark it Accepted. @markshannon @gaogaotiantian

We’ll leave those present even if deprecated or seemingly pointless for the sake of backwards compatibility and can reconsider starting their actual removal with an announcement and multi-release ticking clock at some far future date. We found no need to try and prescribe exactly when that’ll be within PEP 667.

Thanks C API WG for your review and input.  
And thanks Mark and Tian and everyone who has worked on this (including Alyssa via the earlier 558!).

We believe this PEP leads us to a simpler view of namespaces that everyone wants.

---

<div class="post-metadata">

**Author:** ![ksurma](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ksurma/32/30818_2.png) [@ksurma](https://discuss.python.org/u/ksurma)\
**Post date:** [May 10, 2024, 1:21pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/26 "2024-05-10T13:21:31Z")

</div>

Hello,

the implementation of PEP 667 is a part of Python 3.13.0b1.  
I’ve attempted to rebuild all the Fedora Python packages with the new release and found that some of the projects attempt to copy `f_locals`. This, newly, fails as `'FrameLocalsProxy' object has no attribute 'copy'`.  
Before opening a bug report, I’d like to ask whether this is an expected behavior or a regression. It’s not clear to me from the PEP’s description.

Example bug reports to Fedora packages: [murano](https://bugzilla.redhat.com/show_bug.cgi?id=2279983), [bioframe](https://bugzilla.redhat.com/show_bug.cgi?id=2279982).

---

<div class="post-metadata">

**Author:** ![guido](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/guido/32/21_2.png) [@guido](https://discuss.python.org/u/guido)\
**Post date:** [May 10, 2024, 5:13pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/27 "2024-05-10T17:13:51Z")

</div>

Hi Karolina,

Thanks for the bug report.

I consider this a regression that we can fix in beta 2. @gaogaotiantian can you work on this? From the linked bug reports it is now clear that people expect f\_locals.copy() to return a plain dict.

In the meantime, Karonina, a workaround could be to use `dict(frame.f_locals)` instead of `frame.f_locals.copy()`.

–Guido

---

<div class="post-metadata">

**Author:** ![guido](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/guido/32/21_2.png) [@guido](https://discuss.python.org/u/guido)\
**Post date:** [May 10, 2024, 5:24pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/28 "2024-05-10T17:24:57Z")

</div>

Oh, it’s probably also worth clarifying this in the PEP, @gaogaotiantian .

---

<div class="post-metadata">

**Author:** ![gaogaotiantian](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gaogaotiantian/32/12415_2.png) [@gaogaotiantian](https://discuss.python.org/u/gaogaotiantian)\
**Post date:** [May 10, 2024, 5:42pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/29 "2024-05-10T17:42:19Z")

</div>

I’m not sure a single report justifies that users expects `f_locals.copy()` to return a dict. We need to consider the fact that no one knows `f_locals` is a proxy now - everyone thinks it’s a dict, so of course they would expect `f_locals.copy()` to return a dict just like any other dict. However, once people start to realize it’s a write-through proxy, would they expect `f_locals.copy()` to return a snapshot dict, instead of a proxy anymore? I would highly doubt that. `obj.copy()` returning a very different object that has very different features compared to `obj` is not expected.

I think this is a transitional pain we should take, rather than a compromise we should make which would make things confusing when people understand the meaning of the new feature.

---

<div class="post-metadata">

**Author:** ![guido](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/guido/32/21_2.png) [@guido](https://discuss.python.org/u/guido)\
**Post date:** [May 10, 2024, 6:43pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/30 "2024-05-10T18:43:19Z")

</div>

I disagree. Both reports used essentially the same idiom, clearly expecting a snapshot. I don’t want to incur the transitional pain, and the alternative interpretation of `f_locals.copy()` (make another proxy) seems pretty useless – the two proxies would behave exactly the same. So let’s make a snapshot – it’s both more useful and more backwards compatible.

---

<div class="post-metadata">

**Author:** ![gaogaotiantian](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gaogaotiantian/32/12415_2.png) [@gaogaotiantian](https://discuss.python.org/u/gaogaotiantian)\
**Post date:** [May 10, 2024, 7:00pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/31 "2024-05-10T19:00:19Z")

</div>

Do we have any precedence where `type(obj) != type(obj.copy())`?

---

<div class="post-metadata">

**Author:** ![Jelle](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jelle/32/1049_2.png) [@Jelle](https://discuss.python.org/u/Jelle)\
**Post date:** [May 10, 2024, 7:01pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/32 "2024-05-10T19:01:23Z")

</div>

```python
>>> type(MappingProxyType({}).copy())
<class 'dict'>

```

---

<div class="post-metadata">

**Author:** ![gaogaotiantian](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gaogaotiantian/32/12415_2.png) [@gaogaotiantian](https://discuss.python.org/u/gaogaotiantian)\
**Post date:** [May 10, 2024, 7:03pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/33 "2024-05-10T19:03:14Z")

</div>

Okay if the copy of the mapping proxy is a dict then it makes sense.

---

<div class="post-metadata">

**Author:** ![kknechtel](https://avatars.discourse-cdn.com/v4/letter/k/e47c2d/32.png) [@kknechtel](https://discuss.python.org/u/kknechtel)\
**Post date:** [May 10, 2024, 7:39pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/34 "2024-05-10T19:39:38Z")

</div>

It seems to me that if I think something is a dict and I want to copy it, the fact that it’s actually a write-through proxy doesn’t change my mind. If anything, it makes my desire stronger: part of the point of copying is that I can update the copy _without_ writing through to the source.

And yes, more generally I would expect the semantics of a “copy” method on a view (write-through proxy, etc.) to be that I get a separate chunk of data; and it’s not a big deal if I get an instance of the type that was being emulated - since it will have both the expected interface (the view’s methods, plus others I may not care about) and semantics (modifying separate data). E.g. if `memoryview.copy()` existed (I am not proposing here to add it), I would expect either a `bytes` or `bytearray` matching the mutability of the underlying data, or else a `memoryview` _on_ such a new `bytes` or `bytearray`.

---

<div class="post-metadata">

**Author:** ![gaogaotiantian](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gaogaotiantian/32/12415_2.png) [@gaogaotiantian](https://discuss.python.org/u/gaogaotiantian)\
**Post date:** [May 10, 2024, 7:56pm UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/35 "2024-05-10T19:56:03Z")

</div>

Github issue: [gh-118921: Add `copy()` method for `FrameLocalsProxy` by gaogaotiantian · Pull Request #118923 · python/cpython · GitHub](https://github.com/python/cpython/pull/118923)

A PR is made to add the `copy()` method.

---

<div class="post-metadata">

**Author:** ![bluetech](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/bluetech/32/8859_2.png) [@bluetech](https://discuss.python.org/u/bluetech)\
**Post date:** [May 17, 2024, 7:43am UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/36 "2024-05-17T07:43:02Z")

</div>

Pytest has some non-critical (and kinda terrifying) [testing code](https://github.com/pytest-dev/pytest/blob/fdf3aa3fc35ee6d336eafef5016f308b5e57bddb/src/_pytest/pytester.py#L288-L298) like this (paraphrasing):

```py
backlocals = sys._getframe(1).f_locals
eval(..., backlocals, ...)

```

which started failing in Python 3.13 beta with “TypeError: globals must be a real dict; try eval(expr, {}, mapping)”.

I am changing this to `backlocals = dict(sys._getframe(1).f_locals)`, just wanted to leave a note in case this was somehow not intended.

---

<div class="post-metadata">

**Author:** ![ncoghlan](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ncoghlan/32/14266_2.png) [@ncoghlan](https://discuss.python.org/u/ncoghlan)\
**Post date:** [May 22, 2024, 4:43am UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/37 "2024-05-22T04:43:17Z")

</div>

> [@bluetech](#):
>
> I am changing this to `backlocals = dict(sys._getframe(1).f_locals)`, just wanted to leave a note in case this was somehow not intended.

While the website hasn’t updated yet, the following is one of the notes that has been added to the What’s New in 3.13 porting guide:

> Accessing `FrameType.f_locals <frame.f_locals>` in an optimized scope now returns a write-through proxy rather than a snapshot that gets updated at ill-specified times. If a snapshot is desired, it must be created explicitly with `dict` or the proxy’s `.copy()` method.

Anything that requires a real dict falls into that “snapshot is desired” category.

---

<div class="post-metadata">

**Author:** ![guido](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/guido/32/21_2.png) [@guido](https://discuss.python.org/u/guido)\
**Post date:** [May 22, 2024, 5:38am UTC](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631/38 "2024-05-22T05:38:57Z")

</div>

Note that .copy() doesn’t work in beta1. It will work in beta2.

[Previous page](https://discuss.python.org/t/pep-667-consistent-views-of-namespaces/46631.md?page=1)
