gh-151722: Do not track the dict in the GC in _PyDict_FromKeys()#152067
gh-151722: Do not track the dict in the GC in _PyDict_FromKeys()#152067vstinner wants to merge 8 commits into
Conversation
dict_merge() no longer requires the dictionary to be tracked by the GC. Co-authored-by: Donghee Na <donghee.na@python.org>
|
This fix is similar to PR gh-152021 but it doesn't call We don't have to track again the dictionary by the GC on error. For a dict, it's already tracked. For a frozendict, it's ok that it's not tracked by the GC on error. |
|
@vstinner TSAN_OPTIONS=halt_on_error=0 ./python tsan_frozendict.py |
|
@corona10: Could you check with following tests passed with TSAN build? Sure. The test says that issue is fixed: I expect the issue to be fixed since the frozendict is no longer tracked by the GC, at least the one which is modified in-place by I built Python with |
|
I pushed a created = frozendict(x=1)
class DictSubclass(dict):
def __new__(self):
return created
print(type(DictSubclass.fromkeys("abc"))) |
| fd = FrozenDictSubclass.fromkeys("abc") | ||
| self.assertEqual(fd, frozendict(x=1, a=None, b=None, c=None)) | ||
| self.assertEqual(type(fd), FrozenDictSubclass) | ||
| self.assertEqual(type(fd), frozendict) |
There was a problem hiding this comment.
I made the change on purpose. IMO the old behavior is wrong. If FrozenDictSubclass constructor returns a frozendict, .fromkeys() must return a frozendict instead of creating a FrozenDictSubclass.
|
We shouldn't change the behavior of dict and frozendict without a reason, but in this case, the relationship between How about passing a frozendict to the class MyFrozen(frozendict):
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
MyFrozen.fromkeys(["a", "b", "c"])
# => MyFrozen(frozendict({"a": None, "b": None, "c": None}))frozendict is a new type, so we don't need to worry about breaking existing code. |
Call the type constructor with a frozendict for all frozendict subclasses.
Ok. I modified @methane @corona10: Does it look better to you? Sorry, fromkeys() is quite complex because frozendict is immutable :-) At least, the behavior is now well tested by Example: class FrozenDictSubclass(frozendict):
def __new__(cls, *args, **kwargs):
print(f"Call constructor with {args} and {kwargs}")
return super().__new__(cls, *args, **kwargs)
fd = FrozenDictSubclass.fromkeys("abc")
print(fd)
print(type(fd))For a frozendict subclass, the constructor is now called twice: The first call creates an empty frozendict: fromkeys() copies this empty frozendict and fills the copy. The second call is to create a |
Documentation build overview
|
dict_merge() no longer requires the dictionary to be tracked by the GC.