You must break out of the closure:
quadrant = [ (lambda sign: lambda x, y: (sign[0] * x, sign[1] * y) ) (sign)
for sign in ((1, -1), (1, 1), (-1, 1), (-1, -1))]
Or with named functions as Blender pointed out:
def wrapper (sign):
def makeQuadrant (x, y):
return (sign [0] * x, sign [1] * y)
return makeQuadrant
quadrant = [wrapper (sign) for sign in ((1, -1), (1, 1), (-1, 1), (-1, -1))]
Or with a default named parameter as chepner pointed out:
quadrant = [lambda x, y, sign = sign: (sign[0] * x, sign[1] * y)
for sign in ((1, -1), (1, 1), (-1, 1), (-1, -1))]
And now to answer your question:
Why does each new function added to the list replace all the
previously added functions?
No function is replaced, your list contains four distinct functions as you can see here:
quadrant = [lambda x, y: (sign[0] * x, sign[1] * y, id (sign) )
for sign in ((1, -1), (1, 1), (-1, 1), (-1, -1))]
for q in quadrant:
print (id (q) )
What happens is that the value of sign is looked up when the function is called. The current value of sign is the last one assigned during the list comprehension, which is (-1, -1). Which can be seen here:
quadrant = [lambda x, y: (sign[0] * x, sign[1] * y, id (sign) )
for sign in ((1, -1), (1, 1), (-1, 1), (-1, -1))]
for q in quadrant:
print (q (2, 3) )
You might want to look a bit into "scoping" and "closures" for further reading.
Your example basically boils down to this:
fs = [lambda: x for x in range (10) ]
for f in fs: print (f () )