Add __keys__ or __items__ protocol
It is hard to distinguish a sequence and a mapping in Python 3. Both have __getitem__, __len__ and __iter__ methods, but with different semantic. In Python code you can use isinstance() and issubclass() checks against collections.abc.Mapping, but it works only with types which was explicitly registered in Mapping. Autodectection does not work as for Iterable or Hashable. Also importing collections.abc.Mapping and calling PyObject_IsInstance() or PyObject_IsSubclass() is cumbersome and inefficient in the C code. It is rarely used. It is more common to check for the existence of the keys() method. The dict constructor and update() method do this, as well as other code which emulates the behavior of dict. This is the only non-dunder method used by the core operations. There are problems with this: * Since it is not a dunder method, it is not reserved, and may conflicts with the user attribute. * Since it is not a dunder method, it is checked for the instance, not for the type. Instances of the same type can look as a mapping or as not a mapping for the same code. Checking the attribute of the class does not give you information about the attribute of the instance. * There is no a corresponding slot in the type object. So checking the existence of the keys attribute is slow, non-atomic, can execute an arbitrary code and raise an exception. It can't be used in PyMapping_Check() and slows down the dict constructor. * The keys() method is not called in the dict constructor. Just the existence of the keys attribute is checked, its value is not used. * It is a special case. All other implicitly called methods which determined the behavior of builtin types are dunder names. I propose to add support for special methods `__keys__` or `__items__` and corresponding type slot (`tp_mapping->mp_keys` or `tp_mapping->mp_items`). At first stage, the code which checked for "keys" should check also for the special method and use them if defined. At second stage it should emit a warning if "keys" is defined, but the special method is not defined. At third stage, it should use the result of the special method and ignore "keys". PyMapping_Check() can be made checking the corresponding slot. I am not sure about some details: 1. What special method should be added, `__keys__` or `__items__`? The former returns keys, it needs to call `__getitem__` repeatedly to get values. The latter returns key-value pairs, it does not need to call `__getitem__`, but you should always pay the cost of creating a tuple even if you do not need values. 2. What type should they return? * An iterator. * An iterable which can be iterated only once. Easy to implement in Python as generator methods. * An iterable which can be iterated multiple times. * More complex view object which may support other protocols (for example support `__or__` and `__and__`). What do you think about this?
participants (9)
-
Andrew Svetlov
-
Chris Angelico
-
Ethan Furman
-
Guido van Rossum
-
Kyle Stanley
-
Serhiy Storchaka
-
Soni L.
-
Steven D'Aprano
-
waszka23ï¼ gmail.com