A generator can be created using a function that contains a yield
, but can also be returned by other standard python functions such as range()
, map()
and others.
Also (and this is relevant here) by what is called a "generating expression" ( generator expression ), which are similar to the list comprehensions but with parentheses instead of brackets. For example:
>>> numeros = range(10) # numeros es un generador
>>> cuadrados = (x**2 for x in numeros) # cuadrados es otro generador
None of the generators has produced any data yet. They will begin to produce them when we evaluate them in a loop, for example:
>>> for x in cuadrados:
... pass
Then the generator cuadrados
will be executed, and that will also cause the execution of the generator numeros
(which in turn causes the execution of the generator returned by range()
.
A function can receive a generator as a parameter. For example, the sum()
function iterates over the elements returned by the generator and adds them all. So:
>>> sum(cuadrados)
285
Once the generator has been "depleted", it can not be used again (it does not "contain" more elements)
>>> sum(cuadrados)
0
To the function that admits a generator as a parameter, we can pass the generating expression to it, as here:
>>> sum( (x**2 for x in range(10)) )
285
Look at the double parenthesis. We have parentheses to delimit the argument of sum()
and others to delimit the generating expression. When there is no possible ambiguity (that is, when the generating expression is the only argument I am passing to it), these internal parentheses can be omitted. So:
>>> sum(x**2 for x in range(10))
285
However, if the function supports more than one parameter and we want to pass both, I can no longer omit the parentheses around the generating function. For example, sum()
supports a second optional parameter with the initial value of the sum. Then I would call it like this:
>>> sum((x**2 for x in range(10)), 100)
385
If I omit the parentheses in the generating expression, I get an exception:
>>> sum(x**2 for x in range(10), 100)
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
Does this error message ring? Now you know what you had wrong ;-)
Update
Seeking to approach the "ideal solution" sought by the user, and taking into account that Python 3 has eliminated the unpacking of the arguments of a lambda
(also known as destructuration ), the closest would be the following:
def openOrSenior(data):
return list(map(lambda p: (
lambda age, handicap: 'Senior' if (age>54 and handicap>7) else 'Open'
)(*p), data))
As you can see, the trick is to enclose your ideal lambda
in another lambda that receives a single parameter p
, and which I immediately call spending *p
. That asterisk causes the expansion of the tuple p
, and what reaches the lambda
internal is the two values you were looking for.
It is still not the ideal solution, but for my taste it is better than the "waste" that the internal generator supposes and the sum
later.
In any case, python has gradually fled this type of syntax, in favor of list comprehensions . Using one of these your function would look like this:
def openOrSenior(data):
return ['Senior' if (age>54 and handicap>7) else 'Open'
for (age, handicap) in data]
Infinitely more readable for my taste.