Message324060
I only just now realized that `dict.fromkeys('abc').keys() - 'bc'` returns {'a'} instead of raising an error like {*'abc'} - 'bc' would, which is really quite handy.
The __xor__, __and__, and __sub__ methods of dict_keys (and items, assuming no there are no unhashable values) work just as set.symmetric_difference, set.intersection, and set.difference do, respectively.
>>> a, b, c, d = [*map(dict.keys, map(dict.fromkeys, 'abcd'))]
>>> ((a | 'a') | (b & 'b') | (c ^ 'c')) - d
{'b', 'a'}
>>> a, b, c, d = [*map(dict.items, map(dict.fromkeys, 'abcd'))]
>>> ((a | 'a') | (b & 'b') | (c ^ 'c')) - d
{'c', ('a', None), 'a', ('c', None)}
However, set objects are arbitrarily restricted to taking a set object for the second argument on these functions. As for the first example here, there is even code specifically there to handle a dictionary as the second argument, but it is unreachable when called through the dunder version.
{<class 'list'>, <class 'dict'>, <class 'set'>}
>>> {list, set} | dict.fromkeys((dict, set))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'set' and 'dict'
>>> {*'abc'}.difference('cde')
{'b', 'a'}
>>> {*'abc'} - set('cde')
{'b', 'a'}
>>> {*'abc'} - 'cde'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'set' and 'str'
>>> {1,2,3}.symmetric_difference(b'\x00')
{0, 1, 2, 3}
>>> {1,2,3} ^ b'\x00'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ^: 'set' and 'bytes'
The sources of set_and, set_sub, and set_xor all look like this. All they do is add a check that the second argument is a set and then simply call the same function their respective non-dunder method uses. They're so identical in fact that set_xor actually calls the exact same C function used in the PyMethodDef for set.symmetric_update:
static PyObject *
set_xor(PySetObject *so, PyObject *other)
{
if (!PyAnySet_Check(so) || !PyAnySet_Check(other))
Py_RETURN_NOTIMPLEMENTED;
return set_symmetric_difference(so, other);
}
static PyMethodDef set_methods[] = {
/* ... */
{"symmetric_difference",(PyCFunction)set_symmetric_difference,
METH_O, symmetric_difference_doc},
/* ... */
};
All that's needed to fix this is to remove a total of 106 characters from setobject.c (4 x " || !PyAnySet_Check(other)"). |
|
Date |
User |
Action |
Args |
2018-08-25 11:37:26 | bup | set | recipients:
+ bup |
2018-08-25 11:37:26 | bup | set | messageid: <1535197046.82.0.56676864532.issue34497@psf.upfronthosting.co.za> |
2018-08-25 11:37:26 | bup | link | issue34497 messages |
2018-08-25 11:37:26 | bup | create | |
|