G
gangesmaster
as we all know, * (asterisk) can be used to "inline" or "flatten" a
tuple into an argument list, i.e.:
def f(a, b, c):
...
x = (1,2,3)
f(*x)
so... mainly for symmetry's sake, why not make a "flattening" operator
that also works outside the context of function calls? for example:
a = (1,2,3)
b = (4,5)
c = (*a, *b) # ==> (1,2,3,4,5)
yeah, a + b would also give you the same result, but it could be used
like format-strings, for "templating" tuples, i.e.
c = (*a, 7, 8, *b)
i used to have a concrete use-case for this feature some time ago, but
i can't recall it now. sorry. still, the main argument is symmetry:
it's a syntactic sugar, but it can be useful sometimes, so why limit it
to function calls only?
allowing it to be a generic operator would make things like this
possible:
f(*args, 7) # an implied last argument, 7, is always passed to the
function
today you have to do
f(*(args + (7,)))
which is quite ugly.
and if you have to sequences, one being a list and the other being a
tuple, e.g.
x = [1,2]
y = (3,4)
you can't just x+y them. in order to concat them you'd have to use
"casting" like
f(*(tuple(x) + y))
instead of
f(*x, *y)
isn't the latter more elegant?
just an idea. i'm sure people could come up with more creative
use-cases of a standard "flattening operator". but even without the
creative use cases -- isn't symmetry strong enough an argument? why are
function calls more important than regular expressions?
and the zen proves my point:
(*) Beautiful is better than ugly --> f(*(args + (7,))) is ugly
(*) Flat is better than nested --> less parenthesis
(*) Sparse is better than dense --> less noise
(*) Readability counts --> again, less noise
(*) Special cases aren't special enough to break the rules --> then why
are function calls so special?
the flattening operator would work on any sequence (having __iter__ or
__next__), not just tuples and lists. one very useful feature i can
thik of is "expanding" generators, i.e.:
print xrange(10) # ==> xrange(10)
print *xrange(10) # ==> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
i mean, python already supports this half-way:.... print args
....(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
so... why can't i just do "print *xrange(10)" directly? defining a
function just to expand a generator? well, i could use
"list(xrange(10))" to expand it, but it's less intuitive. the other way
is list-comprehension, [x for x in xrange(10)], but isn't *xrange(10)
more to-the-point?
also, "There should be one-- and preferably only one --obvious way to
do it"... so which one?
(*) list(xrange(10))
(*) [x for x in xrange(10)]
(*) [].extend(xrange(10))
(*) f(*xrange(10))
they all expand generators, but which is the preferable way?
and imagine this:
f(*xrange(10), 7)
this time you can't do *(xrange(10) + (7,)) as generators do not
support addition... you'd have to do *(tuple(xrange(10)) + (7,)) which
is getting quite long already.
so as you can see, there are many inconsistencies between function-call
expressions and regular expressions, that impose artificial limitations
on the language. after all, the code is already in there to support
function-call expressions. all it takes is adding support for regular
exoressions.
what do you think? should i bring it up to python-dev?
-tomer
tuple into an argument list, i.e.:
def f(a, b, c):
...
x = (1,2,3)
f(*x)
so... mainly for symmetry's sake, why not make a "flattening" operator
that also works outside the context of function calls? for example:
a = (1,2,3)
b = (4,5)
c = (*a, *b) # ==> (1,2,3,4,5)
yeah, a + b would also give you the same result, but it could be used
like format-strings, for "templating" tuples, i.e.
c = (*a, 7, 8, *b)
i used to have a concrete use-case for this feature some time ago, but
i can't recall it now. sorry. still, the main argument is symmetry:
it's a syntactic sugar, but it can be useful sometimes, so why limit it
to function calls only?
allowing it to be a generic operator would make things like this
possible:
f(*args, 7) # an implied last argument, 7, is always passed to the
function
today you have to do
f(*(args + (7,)))
which is quite ugly.
and if you have to sequences, one being a list and the other being a
tuple, e.g.
x = [1,2]
y = (3,4)
you can't just x+y them. in order to concat them you'd have to use
"casting" like
f(*(tuple(x) + y))
instead of
f(*x, *y)
isn't the latter more elegant?
just an idea. i'm sure people could come up with more creative
use-cases of a standard "flattening operator". but even without the
creative use cases -- isn't symmetry strong enough an argument? why are
function calls more important than regular expressions?
and the zen proves my point:
(*) Beautiful is better than ugly --> f(*(args + (7,))) is ugly
(*) Flat is better than nested --> less parenthesis
(*) Sparse is better than dense --> less noise
(*) Readability counts --> again, less noise
(*) Special cases aren't special enough to break the rules --> then why
are function calls so special?
the flattening operator would work on any sequence (having __iter__ or
__next__), not just tuples and lists. one very useful feature i can
thik of is "expanding" generators, i.e.:
print xrange(10) # ==> xrange(10)
print *xrange(10) # ==> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
i mean, python already supports this half-way:.... print args
....(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
so... why can't i just do "print *xrange(10)" directly? defining a
function just to expand a generator? well, i could use
"list(xrange(10))" to expand it, but it's less intuitive. the other way
is list-comprehension, [x for x in xrange(10)], but isn't *xrange(10)
more to-the-point?
also, "There should be one-- and preferably only one --obvious way to
do it"... so which one?
(*) list(xrange(10))
(*) [x for x in xrange(10)]
(*) [].extend(xrange(10))
(*) f(*xrange(10))
they all expand generators, but which is the preferable way?
and imagine this:
f(*xrange(10), 7)
this time you can't do *(xrange(10) + (7,)) as generators do not
support addition... you'd have to do *(tuple(xrange(10)) + (7,)) which
is getting quite long already.
so as you can see, there are many inconsistencies between function-call
expressions and regular expressions, that impose artificial limitations
on the language. after all, the code is already in there to support
function-call expressions. all it takes is adding support for regular
exoressions.
what do you think? should i bring it up to python-dev?
-tomer