New submission from Christian Barcenas:
I noticed an inconsistency today between the dict() documentation vs.
implementation.
The documentation for the dict() built-in [1] states that the function accepts
an optional positional argument that is either a mapping object [2] or an
iterable object [3].
Consider the following:
import collections.abc
class MyIterable(object):
def __init__(self):
self._data = [('one', 1), ('two', 2)]
def __iter__(self):
return iter(self._data)
class MyIterableWithKeysMethod(MyIterable):
def keys(self):
return And now for something completely different
class MyIterableWithKeysAttribute(MyIterable):
keys = It's just a flesh wound!
assert issubclass(MyIterable, collections.abc.Iterable)
assert issubclass(MyIterableWithKeysMethod, collections.abc.Iterable)
assert issubclass(MyIterableWithKeysAttribute, collections.abc.Iterable)
assert not issubclass(MyIterable, collections.abc.Mapping)
assert not issubclass(MyIterableWithKeysMethod, collections.abc.Mapping)
assert not issubclass(MyIterableWithKeysAttribute, collections.abc.Mapping)
# OK
assert dict(MyIterable()) == {'one': 1, 'two': 2}
# Traceback (most recent call last):
# File stdin, line 1, in module
# TypeError: 'MyIterableWithKeysMethod' object is not subscriptable
assert dict(MyIterableWithKeysMethod()) == {'one': 1, 'two': 2}
# Traceback (most recent call last):
# File stdin, line 1, in module
# TypeError: attribute of type 'str' is not callable
assert dict(MyIterableWithKeysAttribute()) == {'one': 1, 'two': 2}
The last two assertions should not fail, and it appears that the offending code
can be found in Objects/dictobject.c's dict_update_common:
else if (arg != NULL) {
_Py_IDENTIFIER(keys);
if (_PyObject_HasAttrId(arg, PyId_keys))
result = PyDict_Merge(self, arg, 1);
else
result = PyDict_MergeFromSeq2(self, arg, 1);
}
PyDict_Merge is used to merge key-value pairs if the optional parameter is a
mapping, and PyDict_MergeFromSeq2 is used if the parameter is an iterable.
My immediate thought was to substitute the _PyObject_HasAttrId call with
PyMapping_Check which I believe would work in 2.7, but due to #5945 I don't
think this fix would work in 3.x.
Thoughts?
[1] https://docs.python.org/3.6/library/stdtypes.html#dict
[2] https://docs.python.org/3.6/glossary.html#term-mapping
[3] https://docs.python.org/3.6/glossary.html#term-iterable
--
assignee: docs@python
components: Documentation, Interpreter Core
messages: 246890
nosy: christian.barcenas, docs@python
priority: normal
severity: normal
status: open
title: dict() built-in fails on iterators with a keys attribute
type: behavior
versions: Python 2.7, Python 3.2, Python 3.3, Python 3.4, Python 3.5, Python 3.6
___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue24659
___
___
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com