mirror of https://github.com/python/cpython
* Checkin remaining documentation
* Add more tests * Refactor and neaten the code a bit. * Rename union_update() to update(). * Improve the algorithms (making them a closer to sets.py).
This commit is contained in:
parent
ceca5d2924
commit
f5f41bf087
|
@ -1071,6 +1071,126 @@ Notes:
|
||||||
\versionadded{2.4}
|
\versionadded{2.4}
|
||||||
\end{description}
|
\end{description}
|
||||||
|
|
||||||
|
\subsection{Set Types \label{types-set}}
|
||||||
|
\obindex{set}
|
||||||
|
|
||||||
|
A \dfn{set} object is an unordered collection of immutable values.
|
||||||
|
Common uses include membership testing, removing duplicates from a sequence,
|
||||||
|
and computing mathematical operations such as intersection, union, difference,
|
||||||
|
and symmetric difference.
|
||||||
|
\versionadded{2.4}
|
||||||
|
|
||||||
|
Like other collections, sets support \code{\var{x} in \var{set}},
|
||||||
|
\code{len(\var{set})}, and \code{for \var{x} in \var{set}}. Being an
|
||||||
|
unordered collection, sets do not record element position or order of
|
||||||
|
insertion. Accordingly, sets do not support indexing, slicing, or
|
||||||
|
other sequence-like behavior.
|
||||||
|
|
||||||
|
There are currently two builtin set types, \class{set} and \class{frozenset}.
|
||||||
|
The \class{set} type is mutable --- the contents can be changed using methods
|
||||||
|
like \method{add()} and \method{remove()}. Since it is mutable, it has no
|
||||||
|
hash value and cannot be used as either a dictionary key or as an element of
|
||||||
|
another set. The \class{frozenset} type is immutable and hashable --- its
|
||||||
|
contents cannot be altered after is created; however, it can be used as
|
||||||
|
a dictionary key or as an element of another set.
|
||||||
|
|
||||||
|
Instances of \class{set} and \class{frozenset} provide the following operations:
|
||||||
|
|
||||||
|
\begin{tableiii}{c|c|l}{code}{Operation}{Equivalent}{Result}
|
||||||
|
\lineiii{len(\var{s})}{}{cardinality of set \var{s}}
|
||||||
|
|
||||||
|
\hline
|
||||||
|
\lineiii{\var{x} in \var{s}}{}
|
||||||
|
{test \var{x} for membership in \var{s}}
|
||||||
|
\lineiii{\var{x} not in \var{s}}{}
|
||||||
|
{test \var{x} for non-membership in \var{s}}
|
||||||
|
\lineiii{\var{s}.issubset(\var{t})}{\code{\var{s} <= \var{t}}}
|
||||||
|
{test whether every element in \var{s} is in \var{t}}
|
||||||
|
\lineiii{\var{s}.issuperset(\var{t})}{\code{\var{s} >= \var{t}}}
|
||||||
|
{test whether every element in \var{t} is in \var{s}}
|
||||||
|
|
||||||
|
\hline
|
||||||
|
\lineiii{\var{s}.union(\var{t})}{\var{s} | \var{t}}
|
||||||
|
{new set with elements from both \var{s} and \var{t}}
|
||||||
|
\lineiii{\var{s}.intersection(\var{t})}{\var{s} \&\ \var{t}}
|
||||||
|
{new set with elements common to \var{s} and \var{t}}
|
||||||
|
\lineiii{\var{s}.difference(\var{t})}{\var{s} - \var{t}}
|
||||||
|
{new set with elements in \var{s} but not in \var{t}}
|
||||||
|
\lineiii{\var{s}.symmetric_difference(\var{t})}{\var{s} \^\ \var{t}}
|
||||||
|
{new set with elements in either \var{s} or \var{t} but not both}
|
||||||
|
\lineiii{\var{s}.copy()}{}
|
||||||
|
{new set with a shallow copy of \var{s}}
|
||||||
|
\end{tableiii}
|
||||||
|
|
||||||
|
Note, the non-operator versions of \method{union()}, \method{intersection()},
|
||||||
|
\method{difference()}, and \method{symmetric_difference()},
|
||||||
|
\method{issubset()}, and \method{issuperset()} methods will accept any
|
||||||
|
iterable as an argument. In contrast, their operator based counterparts
|
||||||
|
require their arguments to be sets. This precludes error-prone constructions
|
||||||
|
like \code{set('abc') \&\ 'cbs'} in favor of the more readable
|
||||||
|
\code{set('abc').intersection('cbs')}.
|
||||||
|
|
||||||
|
Both \class{set} and \class{frozenset} support set to set comparisons.
|
||||||
|
Two sets are equal if and only if every element of each set is contained in
|
||||||
|
the other (each is a subset of the other).
|
||||||
|
A set is less than another set if and only if the first set is a proper
|
||||||
|
subset of the second set (is a subset, but is not equal).
|
||||||
|
A set is greater than another set if and only if the first set is a proper
|
||||||
|
superset of the second set (is a superset, but is not equal).
|
||||||
|
|
||||||
|
The subset and equality comparisons do not generalize to a complete
|
||||||
|
ordering function. For example, any two disjoint sets are not equal and
|
||||||
|
are not subsets of each other, so \emph{all} of the following return
|
||||||
|
\code{False}: \code{\var{a}<\var{b}}, \code{\var{a}==\var{b}}, or
|
||||||
|
\code{\var{a}>\var{b}}.
|
||||||
|
Accordingly, sets do not implement the \method{__cmp__} method.
|
||||||
|
|
||||||
|
Since sets only define partial ordering (subset relationships), the output
|
||||||
|
of the \method{list.sort()} method is undefined for lists of sets.
|
||||||
|
|
||||||
|
For convenience in implementing sets of sets, the \method{__contains__()},
|
||||||
|
\method{remove()}, and \method{discard()} methods automatically match
|
||||||
|
instances of the \class{set} class their \class{frozenset} counterparts
|
||||||
|
inside a set. For example, \code{set('abc') in set([frozenset('abc')])}
|
||||||
|
returns \code{True}.
|
||||||
|
|
||||||
|
The following table lists operations available for \class{set}
|
||||||
|
that do not apply to immutable instances of \class{frozenset}:
|
||||||
|
|
||||||
|
\begin{tableiii}{c|c|l}{code}{Operation}{Equivalent}{Result}
|
||||||
|
\lineiii{\var{s}.update(\var{t})}
|
||||||
|
{\var{s} |= \var{t}}
|
||||||
|
{return set \var{s} with elements added from \var{t}}
|
||||||
|
\lineiii{\var{s}.intersection_update(\var{t})}
|
||||||
|
{\var{s} \&= \var{t}}
|
||||||
|
{return set \var{s} keeping only elements also found in \var{t}}
|
||||||
|
\lineiii{\var{s}.difference_update(\var{t})}
|
||||||
|
{\var{s} -= \var{t}}
|
||||||
|
{return set \var{s} after removing elements found in \var{t}}
|
||||||
|
\lineiii{\var{s}.symmetric_difference_update(\var{t})}
|
||||||
|
{\var{s} \textasciicircum= \var{t}}
|
||||||
|
{return set \var{s} with elements from \var{s} or \var{t}
|
||||||
|
but not both}
|
||||||
|
|
||||||
|
\hline
|
||||||
|
\lineiii{\var{s}.add(\var{x})}{}
|
||||||
|
{add element \var{x} to set \var{s}}
|
||||||
|
\lineiii{\var{s}.remove(\var{x})}{}
|
||||||
|
{remove \var{x} from set \var{s}; raises KeyError if not present}
|
||||||
|
\lineiii{\var{s}.discard(\var{x})}{}
|
||||||
|
{removes \var{x} from set \var{s} if present}
|
||||||
|
\lineiii{\var{s}.pop()}{}
|
||||||
|
{remove and return an arbitrary element from \var{s}; raises
|
||||||
|
\exception{KeyError} if empty}
|
||||||
|
\lineiii{\var{s}.clear()}{}
|
||||||
|
{remove all elements from set \var{s}}
|
||||||
|
\end{tableiii}
|
||||||
|
|
||||||
|
Note, the non-operator versions of the \method{update()},
|
||||||
|
\method{intersection_update()}, \method{difference_update()}, and
|
||||||
|
\method{symmetric_difference_update()} methods will accept any iterable
|
||||||
|
as an argument.
|
||||||
|
|
||||||
|
|
||||||
\subsection{Mapping Types \label{typesmapping}}
|
\subsection{Mapping Types \label{typesmapping}}
|
||||||
\obindex{mapping}
|
\obindex{mapping}
|
||||||
|
|
|
@ -20,7 +20,7 @@ typedef struct {
|
||||||
PyAPI_DATA(PyTypeObject) PySet_Type;
|
PyAPI_DATA(PyTypeObject) PySet_Type;
|
||||||
PyAPI_DATA(PyTypeObject) PyFrozenSet_Type;
|
PyAPI_DATA(PyTypeObject) PyFrozenSet_Type;
|
||||||
|
|
||||||
|
#define PyFrozenSet_CheckExact(ob) ((ob)->ob_type == &PyFrozenSet_Type)
|
||||||
#define PyAnySet_Check(ob) \
|
#define PyAnySet_Check(ob) \
|
||||||
((ob)->ob_type == &PySet_Type || (ob)->ob_type == &PyFrozenSet_Type || \
|
((ob)->ob_type == &PySet_Type || (ob)->ob_type == &PyFrozenSet_Type || \
|
||||||
PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \
|
PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \
|
||||||
|
|
|
@ -46,6 +46,11 @@ class TestJointOps(unittest.TestCase):
|
||||||
self.assertEqual(type(u), self.thetype)
|
self.assertEqual(type(u), self.thetype)
|
||||||
self.assertRaises(PassThru, self.s.union, check_pass_thru())
|
self.assertRaises(PassThru, self.s.union, check_pass_thru())
|
||||||
self.assertRaises(TypeError, self.s.union, [[]])
|
self.assertRaises(TypeError, self.s.union, [[]])
|
||||||
|
for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
|
||||||
|
self.assertEqual(self.thetype('abcba').union(C('cdc')), set('abcd'))
|
||||||
|
self.assertEqual(self.thetype('abcba').union(C('efgfe')), set('abcefg'))
|
||||||
|
self.assertEqual(self.thetype('abcba').union(C('ccb')), set('abc'))
|
||||||
|
self.assertEqual(self.thetype('abcba').union(C('ef')), set('abcef'))
|
||||||
|
|
||||||
def test_or(self):
|
def test_or(self):
|
||||||
i = self.s.union(self.otherword)
|
i = self.s.union(self.otherword)
|
||||||
|
@ -65,6 +70,11 @@ class TestJointOps(unittest.TestCase):
|
||||||
self.assertEqual(self.s, self.thetype(self.word))
|
self.assertEqual(self.s, self.thetype(self.word))
|
||||||
self.assertEqual(type(i), self.thetype)
|
self.assertEqual(type(i), self.thetype)
|
||||||
self.assertRaises(PassThru, self.s.intersection, check_pass_thru())
|
self.assertRaises(PassThru, self.s.intersection, check_pass_thru())
|
||||||
|
for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
|
||||||
|
self.assertEqual(self.thetype('abcba').intersection(C('cdc')), set('cc'))
|
||||||
|
self.assertEqual(self.thetype('abcba').intersection(C('efgfe')), set(''))
|
||||||
|
self.assertEqual(self.thetype('abcba').intersection(C('ccb')), set('bc'))
|
||||||
|
self.assertEqual(self.thetype('abcba').intersection(C('ef')), set(''))
|
||||||
|
|
||||||
def test_and(self):
|
def test_and(self):
|
||||||
i = self.s.intersection(self.otherword)
|
i = self.s.intersection(self.otherword)
|
||||||
|
@ -85,6 +95,11 @@ class TestJointOps(unittest.TestCase):
|
||||||
self.assertEqual(type(i), self.thetype)
|
self.assertEqual(type(i), self.thetype)
|
||||||
self.assertRaises(PassThru, self.s.difference, check_pass_thru())
|
self.assertRaises(PassThru, self.s.difference, check_pass_thru())
|
||||||
self.assertRaises(TypeError, self.s.difference, [[]])
|
self.assertRaises(TypeError, self.s.difference, [[]])
|
||||||
|
for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
|
||||||
|
self.assertEqual(self.thetype('abcba').difference(C('cdc')), set('ab'))
|
||||||
|
self.assertEqual(self.thetype('abcba').difference(C('efgfe')), set('abc'))
|
||||||
|
self.assertEqual(self.thetype('abcba').difference(C('ccb')), set('a'))
|
||||||
|
self.assertEqual(self.thetype('abcba').difference(C('ef')), set('abc'))
|
||||||
|
|
||||||
def test_sub(self):
|
def test_sub(self):
|
||||||
i = self.s.difference(self.otherword)
|
i = self.s.difference(self.otherword)
|
||||||
|
@ -105,6 +120,11 @@ class TestJointOps(unittest.TestCase):
|
||||||
self.assertEqual(type(i), self.thetype)
|
self.assertEqual(type(i), self.thetype)
|
||||||
self.assertRaises(PassThru, self.s.symmetric_difference, check_pass_thru())
|
self.assertRaises(PassThru, self.s.symmetric_difference, check_pass_thru())
|
||||||
self.assertRaises(TypeError, self.s.symmetric_difference, [[]])
|
self.assertRaises(TypeError, self.s.symmetric_difference, [[]])
|
||||||
|
for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
|
||||||
|
self.assertEqual(self.thetype('abcba').symmetric_difference(C('cdc')), set('abd'))
|
||||||
|
self.assertEqual(self.thetype('abcba').symmetric_difference(C('efgfe')), set('abcefg'))
|
||||||
|
self.assertEqual(self.thetype('abcba').symmetric_difference(C('ccb')), set('a'))
|
||||||
|
self.assertEqual(self.thetype('abcba').symmetric_difference(C('ef')), set('abcef'))
|
||||||
|
|
||||||
def test_xor(self):
|
def test_xor(self):
|
||||||
i = self.s.symmetric_difference(self.otherword)
|
i = self.s.symmetric_difference(self.otherword)
|
||||||
|
@ -191,7 +211,8 @@ class TestSet(TestJointOps):
|
||||||
|
|
||||||
def test_clear(self):
|
def test_clear(self):
|
||||||
self.s.clear()
|
self.s.clear()
|
||||||
self.assertEqual(self.s, set([]))
|
self.assertEqual(self.s, set())
|
||||||
|
self.assertEqual(len(self.s), 0)
|
||||||
|
|
||||||
def test_copy(self):
|
def test_copy(self):
|
||||||
dup = self.s.copy()
|
dup = self.s.copy()
|
||||||
|
@ -201,6 +222,9 @@ class TestSet(TestJointOps):
|
||||||
def test_add(self):
|
def test_add(self):
|
||||||
self.s.add('Q')
|
self.s.add('Q')
|
||||||
self.assert_('Q' in self.s)
|
self.assert_('Q' in self.s)
|
||||||
|
dup = self.s.copy()
|
||||||
|
self.s.add('Q')
|
||||||
|
self.assertEqual(self.s, dup)
|
||||||
self.assertRaises(TypeError, self.s.add, [])
|
self.assertRaises(TypeError, self.s.add, [])
|
||||||
|
|
||||||
def test_remove(self):
|
def test_remove(self):
|
||||||
|
@ -231,13 +255,18 @@ class TestSet(TestJointOps):
|
||||||
self.assert_(elem not in self.s)
|
self.assert_(elem not in self.s)
|
||||||
self.assertRaises(KeyError, self.s.pop)
|
self.assertRaises(KeyError, self.s.pop)
|
||||||
|
|
||||||
def test_union_update(self):
|
def test_update(self):
|
||||||
retval = self.s.union_update(self.otherword)
|
retval = self.s.update(self.otherword)
|
||||||
self.assertEqual(retval, None)
|
self.assertEqual(retval, None)
|
||||||
for c in (self.word + self.otherword):
|
for c in (self.word + self.otherword):
|
||||||
self.assert_(c in self.s)
|
self.assert_(c in self.s)
|
||||||
self.assertRaises(PassThru, self.s.union_update, check_pass_thru())
|
self.assertRaises(PassThru, self.s.update, check_pass_thru())
|
||||||
self.assertRaises(TypeError, self.s.union_update, [[]])
|
self.assertRaises(TypeError, self.s.update, [[]])
|
||||||
|
for p, q in (('cdc', 'abcd'), ('efgfe', 'abcefg'), ('ccb', 'abc'), ('ef', 'abcef')):
|
||||||
|
for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
|
||||||
|
s = self.thetype('abcba')
|
||||||
|
self.assertEqual(s.update(C(p)), None)
|
||||||
|
self.assertEqual(s, set(q))
|
||||||
|
|
||||||
def test_ior(self):
|
def test_ior(self):
|
||||||
self.s |= set(self.otherword)
|
self.s |= set(self.otherword)
|
||||||
|
@ -254,6 +283,11 @@ class TestSet(TestJointOps):
|
||||||
self.assert_(c not in self.s)
|
self.assert_(c not in self.s)
|
||||||
self.assertRaises(PassThru, self.s.intersection_update, check_pass_thru())
|
self.assertRaises(PassThru, self.s.intersection_update, check_pass_thru())
|
||||||
self.assertRaises(TypeError, self.s.intersection_update, [[]])
|
self.assertRaises(TypeError, self.s.intersection_update, [[]])
|
||||||
|
for p, q in (('cdc', 'c'), ('efgfe', ''), ('ccb', 'bc'), ('ef', '')):
|
||||||
|
for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
|
||||||
|
s = self.thetype('abcba')
|
||||||
|
self.assertEqual(s.intersection_update(C(p)), None)
|
||||||
|
self.assertEqual(s, set(q))
|
||||||
|
|
||||||
def test_iand(self):
|
def test_iand(self):
|
||||||
self.s &= set(self.otherword)
|
self.s &= set(self.otherword)
|
||||||
|
@ -273,6 +307,12 @@ class TestSet(TestJointOps):
|
||||||
self.assert_(c not in self.s)
|
self.assert_(c not in self.s)
|
||||||
self.assertRaises(PassThru, self.s.difference_update, check_pass_thru())
|
self.assertRaises(PassThru, self.s.difference_update, check_pass_thru())
|
||||||
self.assertRaises(TypeError, self.s.difference_update, [[]])
|
self.assertRaises(TypeError, self.s.difference_update, [[]])
|
||||||
|
self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
|
||||||
|
for p, q in (('cdc', 'ab'), ('efgfe', 'abc'), ('ccb', 'a'), ('ef', 'abc')):
|
||||||
|
for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
|
||||||
|
s = self.thetype('abcba')
|
||||||
|
self.assertEqual(s.difference_update(C(p)), None)
|
||||||
|
self.assertEqual(s, set(q))
|
||||||
|
|
||||||
def test_isub(self):
|
def test_isub(self):
|
||||||
self.s -= set(self.otherword)
|
self.s -= set(self.otherword)
|
||||||
|
@ -292,6 +332,11 @@ class TestSet(TestJointOps):
|
||||||
self.assert_(c not in self.s)
|
self.assert_(c not in self.s)
|
||||||
self.assertRaises(PassThru, self.s.symmetric_difference_update, check_pass_thru())
|
self.assertRaises(PassThru, self.s.symmetric_difference_update, check_pass_thru())
|
||||||
self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
|
self.assertRaises(TypeError, self.s.symmetric_difference_update, [[]])
|
||||||
|
for p, q in (('cdc', 'abd'), ('efgfe', 'abcefg'), ('ccb', 'a'), ('ef', 'abcef')):
|
||||||
|
for C in set, frozenset, dict.fromkeys, str, unicode, list, tuple:
|
||||||
|
s = self.thetype('abcba')
|
||||||
|
self.assertEqual(s.symmetric_difference_update(C(p)), None)
|
||||||
|
self.assertEqual(s, set(q))
|
||||||
|
|
||||||
def test_ixor(self):
|
def test_ixor(self):
|
||||||
self.s ^= set(self.otherword)
|
self.s ^= set(self.otherword)
|
||||||
|
@ -635,7 +680,7 @@ class TestUpdateOps(unittest.TestCase):
|
||||||
self.assertEqual(self.set, set([2, 4, 6, 8]))
|
self.assertEqual(self.set, set([2, 4, 6, 8]))
|
||||||
|
|
||||||
def test_union_method_call(self):
|
def test_union_method_call(self):
|
||||||
self.set.union_update(set([3, 4, 5]))
|
self.set.update(set([3, 4, 5]))
|
||||||
self.assertEqual(self.set, set([2, 3, 4, 5, 6]))
|
self.assertEqual(self.set, set([2, 3, 4, 5, 6]))
|
||||||
|
|
||||||
def test_intersection_subset(self):
|
def test_intersection_subset(self):
|
||||||
|
@ -761,15 +806,15 @@ class TestMutate(unittest.TestCase):
|
||||||
self.failUnless(v in popped)
|
self.failUnless(v in popped)
|
||||||
|
|
||||||
def test_update_empty_tuple(self):
|
def test_update_empty_tuple(self):
|
||||||
self.set.union_update(())
|
self.set.update(())
|
||||||
self.assertEqual(self.set, set(self.values))
|
self.assertEqual(self.set, set(self.values))
|
||||||
|
|
||||||
def test_update_unit_tuple_overlap(self):
|
def test_update_unit_tuple_overlap(self):
|
||||||
self.set.union_update(("a",))
|
self.set.update(("a",))
|
||||||
self.assertEqual(self.set, set(self.values))
|
self.assertEqual(self.set, set(self.values))
|
||||||
|
|
||||||
def test_update_unit_tuple_non_overlap(self):
|
def test_update_unit_tuple_non_overlap(self):
|
||||||
self.set.union_update(("a", "z"))
|
self.set.update(("a", "z"))
|
||||||
self.assertEqual(self.set, set(self.values + ["z"]))
|
self.assertEqual(self.set, set(self.values + ["z"]))
|
||||||
|
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
|
@ -872,7 +917,7 @@ class TestOnlySetsInBinaryOps(unittest.TestCase):
|
||||||
self.assertRaises(TypeError, lambda: self.other > self.set)
|
self.assertRaises(TypeError, lambda: self.other > self.set)
|
||||||
self.assertRaises(TypeError, lambda: self.other >= self.set)
|
self.assertRaises(TypeError, lambda: self.other >= self.set)
|
||||||
|
|
||||||
def test_union_update_operator(self):
|
def test_update_operator(self):
|
||||||
try:
|
try:
|
||||||
self.set |= self.other
|
self.set |= self.other
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
@ -880,11 +925,11 @@ class TestOnlySetsInBinaryOps(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.fail("expected TypeError")
|
self.fail("expected TypeError")
|
||||||
|
|
||||||
def test_union_update(self):
|
def test_update(self):
|
||||||
if self.otherIsIterable:
|
if self.otherIsIterable:
|
||||||
self.set.union_update(self.other)
|
self.set.update(self.other)
|
||||||
else:
|
else:
|
||||||
self.assertRaises(TypeError, self.set.union_update, self.other)
|
self.assertRaises(TypeError, self.set.update, self.other)
|
||||||
|
|
||||||
def test_union(self):
|
def test_union(self):
|
||||||
self.assertRaises(TypeError, lambda: self.set | self.other)
|
self.assertRaises(TypeError, lambda: self.set | self.other)
|
||||||
|
@ -1215,7 +1260,7 @@ class TestVariousIteratorArgs(unittest.TestCase):
|
||||||
|
|
||||||
def test_inplace_methods(self):
|
def test_inplace_methods(self):
|
||||||
for data in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5), 'december'):
|
for data in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5), 'december'):
|
||||||
for methname in ('union_update', 'intersection_update',
|
for methname in ('update', 'intersection_update',
|
||||||
'difference_update', 'symmetric_difference_update'):
|
'difference_update', 'symmetric_difference_update'):
|
||||||
for g in (G, I, Ig, S, L, R):
|
for g in (G, I, Ig, S, L, R):
|
||||||
s = set('january')
|
s = set('january')
|
||||||
|
|
|
@ -12,48 +12,44 @@
|
||||||
static PyObject *
|
static PyObject *
|
||||||
make_new_set(PyTypeObject *type, PyObject *iterable)
|
make_new_set(PyTypeObject *type, PyObject *iterable)
|
||||||
{
|
{
|
||||||
PyObject *data;
|
PyObject *data = NULL;
|
||||||
PyObject *it = NULL;
|
PyObject *it = NULL;
|
||||||
PyObject *item;
|
PyObject *item;
|
||||||
PySetObject *so;
|
PySetObject *so = NULL;
|
||||||
|
|
||||||
/* Get iterator. */
|
/* Get iterator. */
|
||||||
if (iterable != NULL) {
|
if (iterable != NULL) {
|
||||||
it = PyObject_GetIter(iterable);
|
it = PyObject_GetIter(iterable);
|
||||||
if (it == NULL)
|
if (it == NULL)
|
||||||
return NULL;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = PyDict_New();
|
data = PyDict_New();
|
||||||
if (data == NULL) {
|
if (data == NULL)
|
||||||
Py_DECREF(it);
|
goto done;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (it != NULL && (item = PyIter_Next(it)) != NULL) {
|
while (it != NULL && (item = PyIter_Next(it)) != NULL) {
|
||||||
if (PyDict_SetItem(data, item, Py_True) == -1) {
|
if (PyDict_SetItem(data, item, Py_True) == -1) {
|
||||||
Py_DECREF(it);
|
|
||||||
Py_DECREF(data);
|
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
return NULL;
|
goto done;
|
||||||
}
|
}
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
}
|
}
|
||||||
Py_XDECREF(it);
|
if (PyErr_Occurred())
|
||||||
if (PyErr_Occurred()) {
|
goto done;
|
||||||
Py_DECREF(data);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create PySetObject structure */
|
/* create PySetObject structure */
|
||||||
so = (PySetObject *)type->tp_alloc(type, 0);
|
so = (PySetObject *)type->tp_alloc(type, 0);
|
||||||
if (so == NULL) {
|
if (so == NULL)
|
||||||
Py_DECREF(data);
|
goto done;
|
||||||
return NULL;
|
|
||||||
}
|
Py_INCREF(data);
|
||||||
so->data = data;
|
so->data = data;
|
||||||
so->hash = -1;
|
so->hash = -1;
|
||||||
|
|
||||||
|
done:
|
||||||
|
Py_XDECREF(data);
|
||||||
|
Py_XDECREF(it);
|
||||||
return (PyObject *)so;
|
return (PyObject *)so;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +60,7 @@ frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
|
||||||
if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable))
|
if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (iterable != NULL && iterable->ob_type == &PyFrozenSet_Type) {
|
if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
|
||||||
Py_INCREF(iterable);
|
Py_INCREF(iterable);
|
||||||
return iterable;
|
return iterable;
|
||||||
}
|
}
|
||||||
|
@ -161,7 +157,7 @@ set_copy(PySetObject *so)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
frozenset_copy(PySetObject *so)
|
frozenset_copy(PySetObject *so)
|
||||||
{
|
{
|
||||||
if (so->ob_type == &PyFrozenSet_Type) {
|
if (PyFrozenSet_CheckExact(so)) {
|
||||||
Py_INCREF(so);
|
Py_INCREF(so);
|
||||||
return (PyObject *)so;
|
return (PyObject *)so;
|
||||||
}
|
}
|
||||||
|
@ -170,52 +166,6 @@ frozenset_copy(PySetObject *so)
|
||||||
|
|
||||||
PyDoc_STRVAR(copy_doc, "Return a shallow copy of a set.");
|
PyDoc_STRVAR(copy_doc, "Return a shallow copy of a set.");
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
set_union(PySetObject *so, PyObject *other)
|
|
||||||
{
|
|
||||||
PySetObject *result;
|
|
||||||
PyObject *item, *data, *it;
|
|
||||||
|
|
||||||
result = (PySetObject *)set_copy(so);
|
|
||||||
if (result == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (PyAnySet_Check(other)) {
|
|
||||||
if (PyDict_Merge(result->data, ((PySetObject *)other)->data, 0) == -1) {
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return (PyObject *)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
it = PyObject_GetIter(other);
|
|
||||||
if (it == NULL) {
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
data = result->data;
|
|
||||||
while ((item = PyIter_Next(it)) != NULL) {
|
|
||||||
if (PyDict_SetItem(data, item, Py_True) == -1) {
|
|
||||||
Py_DECREF(it);
|
|
||||||
Py_DECREF(result);
|
|
||||||
Py_DECREF(item);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Py_DECREF(item);
|
|
||||||
}
|
|
||||||
Py_DECREF(it);
|
|
||||||
if (PyErr_Occurred()) {
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return (PyObject *)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(union_doc,
|
|
||||||
"Return the union of two sets as a new set.\n\
|
|
||||||
\n\
|
|
||||||
(i.e. all elements that are in either set.)");
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_union_update(PySetObject *so, PyObject *other)
|
set_union_update(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
|
@ -224,8 +174,7 @@ set_union_update(PySetObject *so, PyObject *other)
|
||||||
if (PyAnySet_Check(other)) {
|
if (PyAnySet_Check(other)) {
|
||||||
if (PyDict_Merge(so->data, ((PySetObject *)other)->data, 0) == -1)
|
if (PyDict_Merge(so->data, ((PySetObject *)other)->data, 0) == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_INCREF(so);
|
Py_RETURN_NONE;
|
||||||
return (PyObject *)so;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it = PyObject_GetIter(other);
|
it = PyObject_GetIter(other);
|
||||||
|
@ -250,6 +199,29 @@ set_union_update(PySetObject *so, PyObject *other)
|
||||||
PyDoc_STRVAR(union_update_doc,
|
PyDoc_STRVAR(union_update_doc,
|
||||||
"Update a set with the union of itself and another.");
|
"Update a set with the union of itself and another.");
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_union(PySetObject *so, PyObject *other)
|
||||||
|
{
|
||||||
|
PySetObject *result;
|
||||||
|
PyObject *rv;
|
||||||
|
|
||||||
|
result = (PySetObject *)set_copy(so);
|
||||||
|
if (result == NULL)
|
||||||
|
return NULL;
|
||||||
|
rv = set_union_update(result, other);
|
||||||
|
if (rv == NULL) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_DECREF(rv);
|
||||||
|
return (PyObject *)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(union_doc,
|
||||||
|
"Return the union of two sets as a new set.\n\
|
||||||
|
\n\
|
||||||
|
(i.e. all elements that are in either set.)");
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_or(PySetObject *so, PyObject *other)
|
set_or(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
|
@ -286,6 +258,18 @@ set_intersection(PySetObject *so, PyObject *other)
|
||||||
result = (PySetObject *)make_new_set(so->ob_type, NULL);
|
result = (PySetObject *)make_new_set(so->ob_type, NULL);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
tgtdata = result->data;
|
||||||
|
selfdata = so->data;
|
||||||
|
|
||||||
|
if (PyAnySet_Check(other) &&
|
||||||
|
PyDict_Size(((PySetObject *)other)->data) > PyDict_Size(selfdata)) {
|
||||||
|
selfdata = ((PySetObject *)other)->data;
|
||||||
|
other = (PyObject *)so;
|
||||||
|
} else if (PyDict_Check(other) &&
|
||||||
|
PyDict_Size(other) > PyDict_Size(selfdata)) {
|
||||||
|
selfdata = other;
|
||||||
|
other = so->data;
|
||||||
|
}
|
||||||
|
|
||||||
it = PyObject_GetIter(other);
|
it = PyObject_GetIter(other);
|
||||||
if (it == NULL) {
|
if (it == NULL) {
|
||||||
|
@ -293,8 +277,6 @@ set_intersection(PySetObject *so, PyObject *other)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
selfdata = so->data;
|
|
||||||
tgtdata = result->data;
|
|
||||||
while ((item = PyIter_Next(it)) != NULL) {
|
while ((item = PyIter_Next(it)) != NULL) {
|
||||||
if (PySequence_Contains(selfdata, item)) {
|
if (PySequence_Contains(selfdata, item)) {
|
||||||
if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
|
if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
|
||||||
|
@ -390,27 +372,39 @@ set_iand(PySetObject *so, PyObject *other)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_difference(PySetObject *so, PyObject *other)
|
set_difference(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
PySetObject *result;
|
PySetObject *result, *otherset=NULL;
|
||||||
PyObject *item, *tgtdata, *it;
|
PyObject *item, *otherdata, *tgtdata, *it;
|
||||||
|
|
||||||
result = (PySetObject *)set_copy(so);
|
result = (PySetObject *)make_new_set(so->ob_type, NULL);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
tgtdata = result->data;
|
||||||
|
|
||||||
it = PyObject_GetIter(other);
|
if (PyDict_Check(other))
|
||||||
|
otherdata = other;
|
||||||
|
else if (PyAnySet_Check(other))
|
||||||
|
otherdata = ((PySetObject *)other)->data;
|
||||||
|
else {
|
||||||
|
otherset = (PySetObject *)make_new_set(so->ob_type, other);
|
||||||
|
if (otherset == NULL) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
otherdata = otherset->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
it = PyObject_GetIter(so->data);
|
||||||
if (it == NULL) {
|
if (it == NULL) {
|
||||||
|
Py_XDECREF(otherset);
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tgtdata = result->data;
|
|
||||||
while ((item = PyIter_Next(it)) != NULL) {
|
while ((item = PyIter_Next(it)) != NULL) {
|
||||||
if (PyDict_DelItem(tgtdata, item) == -1) {
|
if (!PySequence_Contains(otherdata, item)) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_KeyError))
|
if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
|
||||||
PyErr_Clear();
|
Py_XDECREF(otherset);
|
||||||
else {
|
|
||||||
Py_DECREF(it);
|
Py_DECREF(it);
|
||||||
Py_DECREF(result);
|
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -418,6 +412,7 @@ set_difference(PySetObject *so, PyObject *other)
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
}
|
}
|
||||||
Py_DECREF(it);
|
Py_DECREF(it);
|
||||||
|
Py_XDECREF(otherset);
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -488,66 +483,6 @@ set_isub(PySetObject *so, PyObject *other)
|
||||||
return (PyObject *)so;
|
return (PyObject *)so;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
set_symmetric_difference(PySetObject *so, PyObject *other)
|
|
||||||
{
|
|
||||||
PySetObject *result, *otherset=NULL;
|
|
||||||
PyObject *item, *selfdata, *otherdata, *tgtdata, *it;
|
|
||||||
|
|
||||||
selfdata = so->data;
|
|
||||||
|
|
||||||
result = (PySetObject *)set_copy(so);
|
|
||||||
if (result == NULL)
|
|
||||||
return NULL;
|
|
||||||
tgtdata = result->data;
|
|
||||||
|
|
||||||
if (PyDict_Check(other))
|
|
||||||
otherdata = other;
|
|
||||||
else if (PyAnySet_Check(other))
|
|
||||||
otherdata = ((PySetObject *)other)->data;
|
|
||||||
else {
|
|
||||||
otherset = (PySetObject *)make_new_set(so->ob_type, other);
|
|
||||||
if (otherset == NULL) {
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
otherdata = otherset->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
it = PyObject_GetIter(otherdata);
|
|
||||||
if (it == NULL) {
|
|
||||||
Py_XDECREF(otherset);
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((item = PyIter_Next(it)) != NULL) {
|
|
||||||
if (PyDict_DelItem(tgtdata, item) == -1) {
|
|
||||||
PyErr_Clear();
|
|
||||||
if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
|
|
||||||
Py_DECREF(it);
|
|
||||||
Py_XDECREF(otherset);
|
|
||||||
Py_DECREF(result);
|
|
||||||
Py_DECREF(item);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Py_DECREF(item);
|
|
||||||
}
|
|
||||||
Py_DECREF(it);
|
|
||||||
Py_XDECREF(otherset);
|
|
||||||
if (PyErr_Occurred()) {
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return (PyObject *)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(symmetric_difference_doc,
|
|
||||||
"Return the symmetric difference of two sets as a new set.\n\
|
|
||||||
\n\
|
|
||||||
(i.e. all elements that are in exactly one of the sets.)");
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_symmetric_difference_update(PySetObject *so, PyObject *other)
|
set_symmetric_difference_update(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
|
@ -599,6 +534,83 @@ set_symmetric_difference_update(PySetObject *so, PyObject *other)
|
||||||
PyDoc_STRVAR(symmetric_difference_update_doc,
|
PyDoc_STRVAR(symmetric_difference_update_doc,
|
||||||
"Update a set with the symmetric difference of itself and another.");
|
"Update a set with the symmetric difference of itself and another.");
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
set_symmetric_difference(PySetObject *so, PyObject *other)
|
||||||
|
{
|
||||||
|
PySetObject *result;
|
||||||
|
PyObject *item, *selfdata, *otherdata, *tgtdata, *it, *rv, *otherset;
|
||||||
|
|
||||||
|
if (PyDict_Check(other))
|
||||||
|
otherdata = other;
|
||||||
|
else if (PyAnySet_Check(other))
|
||||||
|
otherdata = ((PySetObject *)other)->data;
|
||||||
|
else {
|
||||||
|
otherset = make_new_set(so->ob_type, other);
|
||||||
|
if (otherset == NULL)
|
||||||
|
return NULL;
|
||||||
|
rv = set_symmetric_difference_update((PySetObject *)otherset, (PyObject *)so);
|
||||||
|
if (rv == NULL)
|
||||||
|
return NULL;
|
||||||
|
Py_DECREF(rv);
|
||||||
|
return otherset;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = (PySetObject *)make_new_set(so->ob_type, NULL);
|
||||||
|
if (result == NULL)
|
||||||
|
return NULL;
|
||||||
|
tgtdata = result->data;
|
||||||
|
selfdata = so->data;
|
||||||
|
|
||||||
|
it = PyObject_GetIter(otherdata);
|
||||||
|
if (it == NULL) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
while ((item = PyIter_Next(it)) != NULL) {
|
||||||
|
if (!PySequence_Contains(selfdata, item)) {
|
||||||
|
if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
|
||||||
|
Py_DECREF(it);
|
||||||
|
Py_DECREF(item);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_DECREF(item);
|
||||||
|
}
|
||||||
|
Py_DECREF(it);
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
it = PyObject_GetIter(selfdata);
|
||||||
|
if (it == NULL) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
while ((item = PyIter_Next(it)) != NULL) {
|
||||||
|
if (!PySequence_Contains(otherdata, item)) {
|
||||||
|
if (PyDict_SetItem(tgtdata, item, Py_True) == -1) {
|
||||||
|
Py_DECREF(it);
|
||||||
|
Py_DECREF(item);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_DECREF(item);
|
||||||
|
}
|
||||||
|
Py_DECREF(it);
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
Py_DECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (PyObject *)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(symmetric_difference_doc,
|
||||||
|
"Return the symmetric difference of two sets as a new set.\n\
|
||||||
|
\n\
|
||||||
|
(i.e. all elements that are in exactly one of the sets.)");
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
set_xor(PySetObject *so, PyObject *other)
|
set_xor(PySetObject *so, PyObject *other)
|
||||||
{
|
{
|
||||||
|
@ -1012,7 +1024,7 @@ static PyMethodDef set_methods[] = {
|
||||||
symmetric_difference_update_doc},
|
symmetric_difference_update_doc},
|
||||||
{"union", (PyCFunction)set_union, METH_O,
|
{"union", (PyCFunction)set_union, METH_O,
|
||||||
union_doc},
|
union_doc},
|
||||||
{"union_update",(PyCFunction)set_union_update, METH_O,
|
{"update", (PyCFunction)set_union_update, METH_O,
|
||||||
union_update_doc},
|
union_update_doc},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
@ -1159,8 +1171,7 @@ PyTypeObject PyFrozenSet_Type = {
|
||||||
0, /* ob_size */
|
0, /* ob_size */
|
||||||
"frozenset", /* tp_name */
|
"frozenset", /* tp_name */
|
||||||
sizeof(PySetObject), /* tp_basicsize */
|
sizeof(PySetObject), /* tp_basicsize */
|
||||||
0, /* tp_itemsize */
|
0, /* tp_itemsize */ /* methods */
|
||||||
/* methods */
|
|
||||||
(destructor)set_dealloc, /* tp_dealloc */
|
(destructor)set_dealloc, /* tp_dealloc */
|
||||||
(printfunc)set_tp_print, /* tp_print */
|
(printfunc)set_tp_print, /* tp_print */
|
||||||
0, /* tp_getattr */
|
0, /* tp_getattr */
|
||||||
|
|
Loading…
Reference in New Issue