New submission from Dan Snider <mr.assume.a...@gmail.com>:
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)"). ---------- components: Interpreter Core, Library (Lib) messages: 324060 nosy: bup priority: normal severity: normal status: open title: Remove needless set operator restriction type: enhancement versions: Python 3.7, Python 3.8 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue34497> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com