Re: Idiomatic Python for incrementing pairs
On Fri, 07 Jun 2013 21:32:39 -0500, Tim Chase wrote: Playing around, I've been trying to figure out the most pythonic way of incrementing multiple values based on the return of a function. Something like [...skip misleading and irrelevant calculate() function...] alpha = beta = 0 temp_a, temp_b = calculate(...) alpha += temp_a beta += temp_b Is there a better way to do this without holding each temporary result before using it to increment? Not really. The above idiom is not really terribly Pythonic. It's more like the sort of old-fashioned procedural code I'd write in Pascal or COBOL or similar. For just two variables, it's not so bad, although I'd probably save a line and a temporary variable and write it as this: alpha = beta = 0 tmp = calculate(...) alpha, beta = alpha+tmp[0], beta+tmp[1] But if you have many such values, that's a sign that you're doing it wrong. Do it like this instead: values = [0]*17 # or however many variables you have increments = calculate(...) values = [a+b for a,b in zip(values, increments)] Or define a helper function: add(v1, v2): Vector addition. add([1, 2], [4, 5]) [5, 7] return [a+b for a,b in zip(v1, v2)] values = [0]*17 increments = calculate(...) values = add(values, increments) Much nicer! And finally, if speed is absolutely critical, this scales to using fast vector libraries like numpy. Just use numpy arrays instead of lists, and + instead of the add helper function, and Bob's yer uncle. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Idiomatic Python for incrementing pairs
Tim Chase wrote: On 2013-06-07 23:46, Jason Swails wrote: On Fri, Jun 7, 2013 at 10:32 PM, Tim Chase def calculate(params): a = b = 0 if some_calculation(params): a += 1 if other_calculation(params): b += 1 return (a, b) alpha = beta = 0 temp_a, temp_b = calculate(...) alpha += temp_a beta += temp_b Is there a better way to do this without holding each temporary result before using it to increment? alpha = beta = 0 alpha, beta = (sum(x) for x in zip( (alpha, beta), calculate(...) ) ) Yeah, I came up with something similar, but it was so opaque I fell back to the more readable version I had above. With only the two variables to increment in this case, the overhead of duplicating code doesn't seem as worth it as it might be if there were umpteen counters being returned as a tuple and umpteen corresponding variables being updated (at which point, it might make more sense to switch to another data structure like a dict). Ah well. Glad to see at least I'm not the only one stymied by trying to make it more pythonic while at least keeping it readable. -tkc You can hide the complexity in a custom class: class T(tuple): ... def __add__(self, other): ... return T((a+b) for a, b in zip(self, other)) ... t = T((0, 0)) for pair in [(1, 10), (2, 20), (3, 30)]: ... t += pair ... t (6, 60) (If you are already using numpy you can do the above with a numpy.array instead of writing your own T.) -- http://mail.python.org/mailman/listinfo/python-list
Re: Idiomatic Python for incrementing pairs
On Sat, Jun 8, 2013 at 2:47 AM, Peter Otten __pete...@web.de wrote: You can hide the complexity in a custom class: class T(tuple): ... def __add__(self, other): ... return T((a+b) for a, b in zip(self, other)) ... t = T((0, 0)) for pair in [(1, 10), (2, 20), (3, 30)]: ... t += pair ... t (6, 60) (If you are already using numpy you can do the above with a numpy.array instead of writing your own T.) I do this frequently when I want data structures that behave like vectors but don't want to impose the numpy dependency on users. (Although I usually inherit from a mutable sequence so I can override __iadd__ and __isub__). It seemed overkill for the provided example, though... All the best, Jason -- http://mail.python.org/mailman/listinfo/python-list
Re: Idiomatic Python for incrementing pairs
On 6/8/2013 12:16 AM, Tim Chase wrote: On 2013-06-08 07:04, Carlos Nepomuceno wrote: alpha, beta = (1 if some_calculation(params) else 0, 1 if other_calculation(params) else 0) This one sets them to absolute values, rather than the incrementing functionality in question: alpha += temp_a beta += temp_b The actual code in question does the initialization outside a loop: alphas_updated = betas_updated = 0 for thing in bunch_of_things: a, b = process(thing) alphas_updated += a betas_updated += b I am pretty sure that this is the faster way to get the result. and it just bugs me as being a little warty for having temp variables when Python does things like tuple-unpacking so elegantly. So use it ;-). That said, as mentioned in a contemporaneous reply to Jason, I haven't found anything better that is still readable. The generalization of what you want is a mutable vector with an in-place augmented assignment version of element by element addition. That probably has been written. Nnmpy arrays do vector addition and maybe do it in-place also (I just do ot know). But here is a custom class for the problem you presented. def process(val): return val, 2*val class Pair(list): def __init__(self, a, b): self.append(a) self.append(b) def inc(self, a, b): self[0] += a self[1] += b pair = Pair(0, 0) for val in [1,2,3]: pair.inc(*process(val)) print(pair) [6, 12] This is cleaner but a bit slower than your in-lined version. I did not use __iadd__ and += because unpacking 'other' (here the process return) in the call does the error checking ('exactly two values') for 'free'. -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: Idiomatic Python for incrementing pairs
On Fri, Jun 7, 2013 at 10:32 PM, Tim Chase python.l...@tim.thechases.comwrote: Playing around, I've been trying to figure out the most pythonic way of incrementing multiple values based on the return of a function. Something like def calculate(params): a = b = 0 if some_calculation(params): a += 1 if other_calculation(params): b += 1 return (a, b) alpha = beta = 0 temp_a, temp_b = calculate(...) alpha += temp_a beta += temp_b Is there a better way to do this without holding each temporary result before using it to increment? alpha = beta = 0 alpha, beta = (sum(x) for x in zip( (alpha, beta), calculate(...) ) ) It saves a couple lines of code, but at the expense of readability IMO. If I was reading the first, I'd know exactly what was happening immediately. If I was reading the second, it would take a bit to decipher. In this example, I don't see a better solution to what you're doing. All the best, Jason -- http://mail.python.org/mailman/listinfo/python-list
Re: Idiomatic Python for incrementing pairs
On Sat, Jun 8, 2013 at 12:32 PM, Tim Chase python.l...@tim.thechases.com wrote: def calculate(params): a = b = 0 if some_calculation(params): a += 1 if other_calculation(params): b += 1 return (a, b) alpha = beta = 0 temp_a, temp_b = calculate(...) alpha += temp_a beta += temp_b Is there a better way to do this without holding each temporary result before using it to increment? Can you pass the function a list with the appropriate values in them, and have it return them via that? def calculate(params, sums): if some_calculation(params): sums[0] += 1 if other_calculation(params): sums[1] += 1 sums = [0, 0] calculate(..., sums) Or use a dictionary if you'd rather they have names, either way. ChrisA -- http://mail.python.org/mailman/listinfo/python-list
RE: Idiomatic Python for incrementing pairs
alpha, beta = (1 if some_calculation(params) else 0, 1 if other_calculation(params) else 0) Date: Fri, 7 Jun 2013 21:32:39 -0500 From: python.l...@tim.thechases.com To: python-list@python.org Subject: Idiomatic Python for incrementing pairs Playing around, I've been trying to figure out the most pythonic way of incrementing multiple values based on the return of a function. Something like def calculate(params): a = b = 0 if some_calculation(params): a += 1 if other_calculation(params): b += 1 return (a, b) alpha = beta = 0 temp_a, temp_b = calculate(...) alpha += temp_a beta += temp_b Is there a better way to do this without holding each temporary result before using it to increment? -tkc -- http://mail.python.org/mailman/listinfo/python-list -- http://mail.python.org/mailman/listinfo/python-list
Re: Idiomatic Python for incrementing pairs
On 2013-06-07 23:46, Jason Swails wrote: On Fri, Jun 7, 2013 at 10:32 PM, Tim Chase def calculate(params): a = b = 0 if some_calculation(params): a += 1 if other_calculation(params): b += 1 return (a, b) alpha = beta = 0 temp_a, temp_b = calculate(...) alpha += temp_a beta += temp_b Is there a better way to do this without holding each temporary result before using it to increment? alpha = beta = 0 alpha, beta = (sum(x) for x in zip( (alpha, beta), calculate(...) ) ) Yeah, I came up with something similar, but it was so opaque I fell back to the more readable version I had above. With only the two variables to increment in this case, the overhead of duplicating code doesn't seem as worth it as it might be if there were umpteen counters being returned as a tuple and umpteen corresponding variables being updated (at which point, it might make more sense to switch to another data structure like a dict). Ah well. Glad to see at least I'm not the only one stymied by trying to make it more pythonic while at least keeping it readable. -tkc -- http://mail.python.org/mailman/listinfo/python-list
Re: Idiomatic Python for incrementing pairs
On 2013-06-08 07:04, Carlos Nepomuceno wrote: alpha, beta = (1 if some_calculation(params) else 0, 1 if other_calculation(params) else 0) This one sets them to absolute values, rather than the incrementing functionality in question: alpha += temp_a beta += temp_b The actual code in question does the initialization outside a loop: alphas_updated = betas_updated = 0 for thing in bunch_of_things: a, b = process(thing) alphas_updated += a betas_updated += b and it just bugs me as being a little warty for having temp variables when Python does things like tuple-unpacking so elegantly. That said, as mentioned in a contemporaneous reply to Jason, I haven't found anything better that is still readable. -tkc -- http://mail.python.org/mailman/listinfo/python-list
RE: Idiomatic Python for incrementing pairs
Oh! I really though you were just adding 1 or 0 to those variables. In clude the loop next time! ;) You can accumulate the values by doing this instead: alpha, beta = (alpha + (1 if some_calculation(params) else 0), beta + (1 if other_calculation(params) else 0)) Date: Fri, 7 Jun 2013 23:16:22 -0500 From: python.l...@tim.thechases.com To: carlosnepomuc...@outlook.com CC: python-list@python.org Subject: Re: Idiomatic Python for incrementing pairs On 2013-06-08 07:04, Carlos Nepomuceno wrote: alpha, beta = (1 if some_calculation(params) else 0, 1 if other_calculation(params) else 0) This one sets them to absolute values, rather than the incrementing functionality in question: alpha += temp_a beta += temp_b The actual code in question does the initialization outside a loop: alphas_updated = betas_updated = 0 for thing in bunch_of_things: a, b = process(thing) alphas_updated += a betas_updated += b and it just bugs me as being a little warty for having temp variables when Python does things like tuple-unpacking so elegantly. That said, as mentioned in a contemporaneous reply to Jason, I haven't found anything better that is still readable. -tkc -- http://mail.python.org/mailman/listinfo/python-list