This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: PyObject_GetIter does not behave as documented on dict objects
Type: Stage: resolved
Components: Documentation Versions: Python 3.6
process
Status: closed Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Sam De Meyer, docs@python, rhettinger, serhiy.storchaka
Priority: normal Keywords:

Created on 2017-05-09 20:19 by Sam De Meyer, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (4)
msg293346 - (view) Author: Sam De Meyer (Sam De Meyer) Date: 2017-05-09 20:19
According to the docs (https://docs.python.org/3/c-api/object.html) the `PyObject_GetIter` method should be equivalent to the python call `iter(<some_dict>)`, but, when given a dict, the `PyObject_GetIter` returns an iterator over key-value pairs whereas the `iter()` method returns an iterator over keys only.

I tripped over this when giving the `<some_dict>.update()` a dict-like object that does not inherit from the builtin dict and implements its own `__iter__()`.

The `update()` method eventually reaches the following piece of code:
https://hg.python.org/cpython/file/4243df51fe43/Objects/dictobject.c#l2383

>    it = PyObject_GetIter(seq2);
> ...
>        item = PyIter_Next(it);
> ...
>        fast = PySequence_Fast(item, "");
> ...
>        key = PySequence_Fast_GET_ITEM(fast, 0);
>        value = PySequence_Fast_GET_ITEM(fast, 1);

displaying the difference in behaviour between `PyObject_GetIter` and `iter(o)`.
msg293347 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2017-05-09 20:35
I can't believe in this since one-argument iter() just calls PyObject_GetIter().

dict.update() accepts either a dict-like object (which should have the keys() method) or an iterable producing key-value pairs. If your dict-like object doesn't work as expected, check that it has the keys() method.
msg293352 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2017-05-09 21:35
This from the help on dict.update():

 |  update(...)
 |      D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
 |      If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
 |      If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
 |      In either case, this is followed by: for k in F: D[k] = F[k]

Likewise in the source for collections.abc.MutableMapping:

    def update(*args, **kwds):
        ''' D.update([E, ]**F) -> None.  Update D from mapping/iterable E and F.
            If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
            If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
            In either case, this is followed by: for k, v in F.items(): D[k] = v
        '''
        if not args:
            raise TypeError("descriptor 'update' of 'MutableMapping' object "
                            "needs an argument")
        self, *args = args
        if len(args) > 1:
            raise TypeError('update expected at most 1 arguments, got %d' %
                            len(args))
        if args:
            other = args[0]
            if isinstance(other, Mapping):
                for key in other:
                    self[key] = other[key]
            elif hasattr(other, "keys"):
                for key in other.keys():
                    self[key] = other[key]
            else:
                for key, value in other:
                    self[key] = value
        for key, value in kwds.items():
            self[key] = value
msg293456 - (view) Author: Sam De Meyer (Sam De Meyer) Date: 2017-05-10 21:56
You seem to be right, my object was lacking the keys method.

Please excuse me for the false alarm, and thanks for pointing it out.
History
Date User Action Args
2022-04-11 14:58:46adminsetgithub: 74507
2017-05-10 21:56:50Sam De Meyersetstatus: open -> closed

messages: + msg293456
stage: resolved
2017-05-09 21:35:42rhettingersetnosy: + rhettinger
messages: + msg293352
2017-05-09 20:35:36serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg293347
2017-05-09 20:19:39Sam De Meyercreate