Author josh.r
Recipients josh.r
Date 2016-03-03.23:20:42
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <>
Don't know when the problem was introduced, but dictviews_sub is doing:

    tmp = _PyObject_CallMethodId(result, &PyId_difference_update, "O", other);

to implement subtraction (after creating result as a set of the keys in question). That's violating the CallMethod contract though (which states the format string should produce a tuple), and while it looks like CallMethod does fixups when the contract is violated, this creates some very odd behaviors.

With a list, everything is fine:

    >>> d = {0: 'zero', 1: 'one', 2: 'two', 3: 'three'}
    >>> d.keys() - [0, 2]
    {1, 3}
    >>> d.keys() - (0, 2)
    TypeError: 'int' object is not iterable

Basically, the fix up doesn't get applied when you subtract a tuple, so it's as if it's trying to call:

    result.difference_update(*(0, 2))  # Unpacking used to illustrate, effect is  result.difference_update(0, 2)

With the list, it's wrapping to make a one element tuple, so it behaves like:

    result.difference_update(*([0, 2],))  # Unpacking used to illustrate, effect is  result.difference_update([0, 2])

For more details, see

Fix should be to change call line to:

    tmp = _PyObject_CallMethodObjArgsId(result, &PyId_difference_update, other, NULL);

(assuming _PyObject_CallMethodObjArgsId is a thing), or if it's not a thing, to fix the format string to force tuple wrapping:

    tmp = _PyObject_CallMethodId(result, &PyId_difference_update, "(O)", other);
Date User Action Args
2016-03-03 23:20:42josh.rsetrecipients: + josh.r
2016-03-03 23:20:42josh.rsetmessageid: <>
2016-03-03 23:20:42josh.rlinkissue26478 messages
2016-03-03 23:20:42josh.rcreate