On Saturday 13 July 2002 09:12 am, Tim Peters wrote:
... Let's do a set module instead. There's only one hurdle to take for a set module, and that's the issue with using mutable sets as keys. Let's just pick one solution and implement it (my favorite being that sets simply cannot be used as keys, since it's the simplest, and matches dicts and lists).
I want a set module, but if I finish Greg's abandoned work I want sets of sets too. Sets don't have "keys", they're conceptually collections of values, and it would be as odd not to allow sets containing sets as not to allow lists containing lists, or to ban dicts as dict values. Greg needed sets of sets for his work, and I've often faked them too. I'm not going to
I agree that having sets without having sets of sets would not be anywhere as useful.
be paralyzed by that combining mutable sets with sets of sets requires that some uses of set-as-set-element will be expensive, fragile, and/or hard to explain. If you don't want that pain, don't play that game. If you do
What about the following compromise: there are two set types, ImmutableSet and MutableSet, with a common supertype Set. ImmutableSet adds __hash__, while MutableSet adds insert and remove, to the common core of methods inherited from Set, such as __contains__ and __iter__. It's easy to make a MutableSet instance m from an ImmutableSet instance x, such that m == x, either by letting each __init__ accept an argument of the other kind (maybe just a special case of such an __init__ accepting any iterable), or, if that can afford very substantial performance improvements, via ad-hoc methods.
The second part of the puzzle is that hash(x) tries to adapt x to the Hashable protocol before calling x.__hash__. Types that are already hashable adapt to Hashable by just returning the same instance, of course. A MutableSet instance adapts to Hashable by returning the equivalent ImmutableSet.
Since it's apparently too wild an idea to say "adapt to protocol" when one means "adapt to protocol", at least for the next few releases (and that, in the optimistic hypothesis that my future rewrite of the adaptation PEP is favorably received), there will of course need to arise yet another special purpose way to express this same general idea, such as:
class MutableSet(Set): ... def insert(self, item): try: item = item.asSetItem() except AttributeError: pass self.data[item] = True
def asSetItem(self): return ImmutableSet(self)
or the like.