[Python-3000] sets in P3K?
Nick Coghlan
ncoghlan at gmail.com
Sat Apr 29 05:37:29 CEST 2006
Raymond Hettinger wrote:
> The only bump in the road is that the {} notation is so similar to
> dictionaries that care must be taken to keep the two as distinct as
> possible.
Here's a summary of the suggestions we've seen so far for empty sets & dicts
Possibilities for an empty set:
set() - explicit, but kind of 'second-class' compared to (), [] and {}
{} - most obvious option, but currently means dict()
{,} - Guido's already said he thinks this is too ugly
{/} - suggestive of phi, but considered too unintuitive/ugly by some
Possibilities for an empty dict:
dict() - explicit, but kind of 'second-class' compared to (), [] and {}
{} - status quo, but ambiguous given the addition of set literals
{:} - matches non-empty dicts by including ':' to indicate mapping
However, I'm now -0 on having a set literal at all, and it's because I believe
we can solve this problem in a more general fashion that applies to more
functions than just the set() constructor.
Currently, [] and () can appear both standalone or following an expression
(list literals and comprehensions, and subscripting for [], tuple literals and
precedence manipulation, and function calls for ())
{} however, can appear only standalone. It is not permitted for it to follow
an expression. If we change that, we can use it to support an alternate
invocation syntax for functions that currently expect an iterable as their
first argument. "EXPR{ARGS}" would be equivalent to "EXPR((ARGS,))", with the
following differences in the parsing of ARGS:
x:y would be permitted, and map to a 2-tuple (x, y)
x:y:z would be permitted, and map to a 3-tuple (x, y, z)
x=y would be permitted, and map to a 2-tuple ('x', y)
*x would be permitted, and would extend the passed in tuple with x
This could all be done in the front-end parser, with no back-end AST or
compiler changes necessary (although we may decide they're desirable for
optimisation purposes).
Dictionary displays would then be a strict subset of dict{EXPR} and tuple
literals would be equivalent to tuple{EXPR} (although the latter wouldn't need
the trailing comma for singleton tuples). List displays would generally be
equivalent to list{EXPR}, except for list comprehensions, which map to
list(EXPR) (as omitting the parentheses around the genexp would otherwise be
illegal).
A constructor for named tuples, a clean syntax for which is the biggest hurdle
named tuples face, could accept an iterable of name-value pairs, with explicit
construction looking like:
result = named_tuple{x=x, y=y}
return result
Unlike keyword arguments in a normal call, this would preserve the argument
ordering, so we know that result.x is result[0] and result.y is result[1]
Explicitly constructed sets would look like:
set() == set{}
set(x) # No braced equivalent
set([x]) == set{x} # Ignoring list comprehensions
set((x,)) == set{x}
set((a, b, c)) == set{a, b, c}
And it would work for frozenset, too:
frozenset() == frozenset{}
frozenset(x) # No braced equivalent
frozenset([x]) == froxenset{x} # Ignoring list comprehensions
frozenset((x,)) == frozenset{x}
frozenset((a, b, c)) == frozenset{a, b, c}
itertools.cycle is another possible beneficiary, as it becomes easy to cycle
through a simple sequence:
cycle{1, 2, 3} # Infinite cycle through the values 1, 2 and 3
The any and all builtins also become more useful for chained 'or' and 'and' tests:
if all{x, y, z}: return
if any{x, y, z}: return
Joining a known set of strings, or extend a mutable sequence also benefits:
", ".join{x, y, z}
seq.extend{x, y, z}
The sundry set methods that accept iterables also benefit:
s.intersection{1, 2, 3}
s.issuperset{1, 2, 3}
s.update{1, 2, 3}
The question of "accept an iterable or accept *args" goes away - the obvious
way to do it is to accept an iterable, and then use a braced call to
conveniently invoke the call with a literal sequence instead of a pre-existing
iterable.
The signatures of dict and dict.update could optionally be simplified back to
accepting a single mapping or iterable, with the explicit keyword construction
support being moved to the separate {} form.
The 'iterable of 2-tuples or mapping' questions can be addressed by making the
keys(), values() and items() methods officially part of the definition of a
mapping.
So dict.update might simplify to:
try:
items_view = obj.items
except AttributeError:
items = obj
else:
items = items_view()
for key, value in items:
self[key] = value
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://www.boredomandlaziness.org
More information about the Python-3000
mailing list