typeshed
typeshed copied to clipboard
`dict` vs `MutableMapping` in `stdlib` annotations
Today I've noticed that copy.deepcopy requires dict type as memo= argument: https://github.com/python/cpython/blob/main/Lib/copy.py
But, this is actually not quite true, MutableMapping works just fine, because only these methods are used in the implementation:
__setitem__.get
But, I have some mixed feelings about it:
- It is more like an implementation details, no one promises that it will continue to work, some
dictonly magic can be used in any method at almost any time - It is more correct, because custom types do work:
import typing
class My(typing.MutableMapping):
def __init__(self):
self._data = {}
def __getitem__(self, k):
return self._data[k]
def __setitem__(self, k, v):
self._data[k] = v
def __delitem__(self, k):
del self._data[k]
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
import copy
print(copy.deepcopy(1, memo=My())) # 1
So, should we allow MutableMapping / Mapping where dict is too specific?
Or should we keep things more reliable?
only these methods are used
Not necessarily true:
copier = getattr(x, "__deepcopy__", None)
if copier is not None:
y = copier(memo)
An advantage of dict is that when you define a __deepcopy__ method, you can type it as taking a dict, and then you can do anything you would usually do with a dict. Presumably defining custom __deepcopy__ logic is more common than passing in a memo argument explicitly, so IMO convenience and simplicity there is more important.
What about other similar cases? How should we make a decision: dict or (Mutable)Mapping?
What about other similar cases? How should we make a decision:
dictor(Mutable)Mapping?
In general, we should be as permissive as possible in argument annotations if the implementation doesn't explicitly check for a dictionary as opposed to any other mutable mapping.
Closing, as I think the question has been answered :)