[Python-3000] sets in P3K?

Josiah Carlson jcarlson at uci.edu
Thu Apr 27 00:55:43 CEST 2006


"Guido van Rossum" <guido at python.org> wrote:
> On 4/26/06, Josiah Carlson <jcarlson at uci.edu> wrote:
> >
> > Edward Loper <edloper at gradient.cis.upenn.edu> wrote:
> > >
> > > I think that a significant motivation for people that propose set
> > > literals is that the following is just plain ugly:
> > >
> > >     s = set([1,2,3])
> > >
> > > It seems much more natural to write:
> > >
> > >     s = set(1, 2, 3)
> >
> > I agree.
> >
> > > However, it is fairly common to want to build a set from a collection,
> > > an iterator, or a genexp.  With the current notation, all three of these
> > > are easy.  But with this "more natural" notation, they're no longer
> > > possible without resorting to varargs (which would create an unnecessary
> > > imtermediary tuple).
> >
> > Right now you are manually creating an intermediate list or tuple to
> > pass to set, so this wouldn't seem to be a significant change to me
> > (it's just an argument semantic addition).
> 
> I have no idea what you mean by "argument semantic addition".

Arguments to a function have a specified semantic result.  Allow all of
all the previously working argument passing semantics to work as they
always did (sequences), then add a new allowed argument passing semantic.

> I don't think this form (set(1, 2, 3)) will ever fly, because it would
> makes set(x) ambiguous. Currently, this interprets x as an iterable
> and produces a set with the elements produced by iterating over x. But
> if set(x, y) is a set of two elements, then set(x) should be a set of
> one element, *regardless of the type of x*.

The ambiguity isn't when using set(1), it's when using set((1,2)).  set
(1) has one very clear semantic meaning: create a set of one item where
that item is 1.  However, set((1,2)) has two meanings: create a set of
two items, one of those items being 1, the other item being 2 - or
create a set of a single item, where that single item is a tuple.

> Curiously, min() and max() successfully use the same overloading.
> However, these don't have the same problem, because min() or max() of
> one value makes no sense, so it's safe to define these such that if
> they are called with a single argument, the argument is assumed to be
> an iterable. But constructing a set() of one value *does* make sense
> (and already has a meaning) so the overloading fails here.

Indeed, but only with immutable iterable sequences.  Mutable iterable
sequences are unambiguous (they don't hash(), so can't be an entry in
and of themselves).

def _set(*args):
    if len(args) > 1:
        #one unambiguous case
        return set(args)
    arg = args[0]
    try:
        #catches non-sequences
        _ = iter(arg)
    except TypeError:
        #another unambiguous case
        return set((arg,))
    try:
        #catches mutable sequences
        _ = hash(arg) 
    except:
        #unambiguous for non-hashables
        return set(arg)
    else:
        #ambiguous for any immutable iterable sequence...
        return set(arg)

However, being that this is the Py3k list, and the only ambiguous case
is that of a single immutable sequence argument to set(), we could
state an execution semantic and call it sufficient.

Being that set(<immutable iterable sequence>) right now results in the
insertion of each item from that sequence into a new set (set((1,2)) ->
set([1,2]) ), we wouldn't need to change the obvious (at least to some)
meaning, or really "the way it works now" meaning.

On the other hand, I note that both Raymond and Guido are saying -1, so
I'll not push it (though I'm also still against more literal syntax),
even though one can come to an almost obvious signature.


> I find the many attempts to come up with a reasonable way to construct
> a set from a list of given values; I hope that {x, y} can still come
> out as a winner, with set(x) useful to construct a set from a
> pre-existing iterable. Note that set(range(10)) is a set with 10
> elements; {range(10)} of course would be a set with one element.

Or really {tuple(range(10))}?

 - Josiah



More information about the Python-3000 mailing list