Reference variable in assignment: x = foo(?)
I've always found +=, -= and the like to be handy, but I had hoped like so many other things in python there would be a generic form of this functionality. x += 5 could be expressed as x = ? + 5 perhaps.
On Thu, Jul 11, 2013 at 3:39 PM, Corey Sarsfield
I've always found +=, -= and the like to be handy, but I had hoped like so many other things in python there would be a generic form of this functionality.
x += 5 could be expressed as x = ? + 5 perhaps.
Can you flesh this out a bit further? Isn't x += 5 <--> x = x + 5 already defined unless a class specifically does something funny with __iadd__? Cheers, Michael
I came up with the idea after having some code on dicts that looked like: a[b][c] = foo(a[b][c]) So in this case there are twice as many look-ups going on as there need to be, even if a[b][c] were to be pulled out into x. If I were to do: a[b][c] += 1 Would it be doing the lookups twice behind the scenes? On Thu, Jul 11, 2013 at 4:00 PM, R. Michael Weylandt < michael.weylandt@gmail.com> wrote:
On Thu, Jul 11, 2013 at 3:39 PM, Corey Sarsfield
wrote: I've always found +=, -= and the like to be handy, but I had hoped like so many other things in python there would be a generic form of this functionality.
x += 5 could be expressed as x = ? + 5 perhaps.
Can you flesh this out a bit further? Isn't x += 5 <--> x = x + 5 already defined unless a class specifically does something funny with __iadd__?
Cheers, Michael
-- Corey Sarsfield
On Jul 11, 2013, at 14:07, Corey Sarsfield
I came up with the idea after having some code on dicts that looked like:
a[b][c] = foo(a[b][c])
So in this case there are twice as many look-ups going on as there need to be, even if a[b][c] were to be pulled out into x.
If I were to do:
a[b][c] += 1
Would it be doing the lookups twice behind the scenes?
Effectively, the best it could possibly do is something like this: tmp = a[b] tmp,__setitem__('c', tmp.__getitem__('c').__iadd__(1)) So yes, there are two lookups. But if a[b] is a dict... Who cares? The lookup is a hash--which is cached after the first one--plus indexing into an array.
On Thu, Jul 11, 2013 at 4:00 PM, R. Michael Weylandt
wrote: On Thu, Jul 11, 2013 at 3:39 PM, Corey Sarsfield
wrote: I've always found +=, -= and the like to be handy, but I had hoped like so many other things in python there would be a generic form of this functionality.
x += 5 could be expressed as x = ? + 5 perhaps.
Can you flesh this out a bit further? Isn't x += 5 <--> x = x + 5 already defined unless a class specifically does something funny with __iadd__?
Cheers, Michael
-- Corey Sarsfield _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
I don't know if what I miss most is the samething the OP is asking for -
but the idea of re-using a value retrieved in an expression in the
same expression - without the need
to assign to a temporary variable.
Like in:
value = expensive_function(b) if expensive_function(b) else default_value
(of course this is a trivial example - but nonetheless it would require an
extra "if" statement to avoid the double call)
Anyway, the proposed syntax in the O.P. would not suffice for this case.
On 11 July 2013 18:41, Andrew Barnert
On Jul 11, 2013, at 14:07, Corey Sarsfield
wrote: I came up with the idea after having some code on dicts that looked like:
a[b][c] = foo(a[b][c])
So in this case there are twice as many look-ups going on as there need to be, even if a[b][c] were to be pulled out into x.
If I were to do:
a[b][c] += 1
Would it be doing the lookups twice behind the scenes?
Effectively, the best it could possibly do is something like this:
tmp = a[b] tmp,__setitem__('c', tmp.__getitem__('c').__iadd__(1))
So yes, there are two lookups.
But if a[b] is a dict... Who cares? The lookup is a hash--which is cached after the first one--plus indexing into an array.
On Thu, Jul 11, 2013 at 4:00 PM, R. Michael Weylandt
wrote: On Thu, Jul 11, 2013 at 3:39 PM, Corey Sarsfield
wrote: I've always found +=, -= and the like to be handy, but I had hoped like so many other things in python there would be a generic form of this functionality.
x += 5 could be expressed as x = ? + 5 perhaps.
Can you flesh this out a bit further? Isn't x += 5 <--> x = x + 5 already defined unless a class specifically does something funny with __iadd__?
Cheers, Michael
-- Corey Sarsfield
_______________________________________________
Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
On Thu, Jul 11, 2013 at 4:57 PM, Joao S. O. Bueno
I don't know if what I miss most is the samething the OP is asking for - but the idea of re-using a value retrieved in an expression in the same expression - without the need to assign to a temporary variable.
Like in: value = expensive_function(b) if expensive_function(b) else default_value
(of course this is a trivial example - but nonetheless it would require an extra "if" statement to avoid the double call)
How about: value = expensive_function(b) or default_value One call, exact same behavior as you request. Available since Python 1.0. -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th.
Actually, what I wanted was to be able to reference the variable being
assigned to
On Thu, Jul 11, 2013 at 7:07 PM, David Mertz
On Thu, Jul 11, 2013 at 4:57 PM, Joao S. O. Bueno
wrote: I don't know if what I miss most is the samething the OP is asking for - but the idea of re-using a value retrieved in an expression in the same expression - without the need to assign to a temporary variable.
Like in: value = expensive_function(b) if expensive_function(b) else default_value
(of course this is a trivial example - but nonetheless it would require an extra "if" statement to avoid the double call)
How about:
value = expensive_function(b) or default_value
One call, exact same behavior as you request. Available since Python 1.0.
-- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
-- Corey Sarsfield
On Fri, Jul 12, 2013 at 12:51 PM, Corey Sarsfield
Actually, what I wanted was to be able to reference the variable being assigned to
I think I understand what you're trying to say, but it's not something that really exists in Python. With a classic assignment statement: foo = (expression) the previous value of foo is abandoned and a new value bound to that name. What you want is to reference that previous value (presumably with the same potential for NameError or UnboundLocalError if there is none). Effectively, elevate the magic of "foo = 5; foo += 10" to full feature. There HAVE been times when I've wanted something like this, but they're extremely rare. Also, the nature of Python makes the benefit somewhat less than it might be in, say, C++; it's not going to be possible to do the lookups once and keep track of the memory location, because Python simply doesn't work that way. Whether __setitem__ can take advantage of a previous __getitem__ is entirely up to the class. ChrisA
On 11 July 2013 21:07, David Mertz
On Thu, Jul 11, 2013 at 4:57 PM, Joao S. O. Bueno
wrote: ... Like in: value = expensive_function(b) if expensive_function(b) else default_value
(of course this is a trivial example - but nonetheless it would require an extra "if" statement to avoid the double call)
How about:
value = expensive_function(b) or default_value
One call, exact same behavior as you request. Available since Python 1.0.
Because, as a I said, that was a naive example - if the predicate was: value = expensive_function(b) if expensive_function(b) > threshold else default_value There is no way "or" would work - Anyway - just forget about it -let's see where this e-mail thread leads (I worked around this particular issue with a couple of helper simple functions to push the value to a list and return it back )
If you look up "Lenses" in the context of Haskell/Scala, you'll see they're
something similar. It's not exactly the same, but the basic idea is to
reify a gettable/settable variable slot into a first class value. You can
then pass around the object to pass around the get/set-ability, or create
higher-order functions like transform that operate on the reified "slot":
// pseudo-scala to increment something; a macro like this doesn't exist
// but it wouldn't be too hard to write
lens(var).transform(_ + 1) // increment a local
lens(var.member).transform(_ + 1) // increment a member
lens(var(0)(1)).transform(_ + 1) // increment an array; array accesses
in scala use round braces
// could use operator overloading/implicits to make it more concise
var ** (_ + 1) // increment a local
Generally these lenses are used for updating nested immutable data
structures (it gets really verbose/unDRY normally) but it's something
similar to what you want, so if you're looking for this sort of thing, that
would be the place to start. None of this is going to end up in python any
time soon, because it's all still pretty researchy and a solid
implementation is still more "PhD" rather than "weekend hack".
--------------------------------------------------------------------------------------------------------------------------
Another possible solution for the
value = expensive(b) if expensive(b) else default
problem, if you don't want a statement to assign to a temporary variable,
is to use a `let` expression
// raw version
value = (lambda res: res if res else default)(expensive(b))
// with a helper function `let`
value = let(expensive(b))(lambda res: res if res else default)
I'd get skewered at code review if i ever wrote this manually, but I've
actually used this quite a lot in auto-generated code (i.e. macros) where I
want to "assign" to a local value but am unable to create a statement. In
fact, if you want to you can forego assignments entirely in your program
and use nested `let` bindings for everything since they're basically
equivalent.
Then you can start putting the braces outside the `let(...)` as in `(let
...)` because you'll be basically be writing Lisp.
-Haoyi
On Fri, Jul 12, 2013 at 11:02 AM, Joao S. O. Bueno
On 11 July 2013 21:07, David Mertz
wrote: On Thu, Jul 11, 2013 at 4:57 PM, Joao S. O. Bueno
wrote:
... Like in: value = expensive_function(b) if expensive_function(b) else default_value
(of course this is a trivial example - but nonetheless it would require an extra "if" statement to avoid the double call)
How about:
value = expensive_function(b) or default_value
One call, exact same behavior as you request. Available since Python 1.0.
Because, as a I said, that was a naive example - if the predicate was: value = expensive_function(b) if expensive_function(b) > threshold else default_value
There is no way "or" would work - Anyway - just forget about it -let's see where this e-mail thread leads
(I worked around this particular issue with a couple of helper simple functions to push the value to a list and return it back ) _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
On Jul 11, 2013 8:02 PM, "Joao S. O. Bueno"
value = expensive_function(b) or default_value
One call, exact same behavior as you request. Available since Python
1.0.
Because, as a I said, that was a naive example - if the predicate was: value = expensive_function(b) if expensive_function(b) > threshold else default_value
There is no way "or" would work - Anyway - just forget about it -let's see where this e-mail thread leads
value = ([v for v in [expensive_function(b)] if v > threshold] or [default_value])[0] I admit it's not the most elegant, but it works generically. Or just use a temp variable. No shame in doing so.
On 12/07/13 07:07, Corey Sarsfield wrote:
I came up with the idea after having some code on dicts that looked like:
a[b][c] = foo(a[b][c])
So in this case there are twice as many look-ups going on as there need to be, even if a[b][c] were to be pulled out into x.
How do you reason that? You need two sets of lookups however you do it: first you call __getitem__ 'b' and 'c', then you call __setitem__. In the general case, you can't cache the reference 1) because that's not how references work in Python, and 2) even if it were, any of the __getitem__ or __setitem__ calls may have side-effects.
If I were to do:
a[b][c] += 1
Would it be doing the lookups twice behind the scenes?
Easy enough to find out with a helper class: class Test(list): def __getitem__(self, attr): print("Looking up item %s" % attr) return super(Test, self).__getitem__(attr) def __setitem__(self, attr, value): print("Setting item %s to %r" % (attr, value)) return super(Test, self).__setitem__(attr, value) instance = Test([1, 2, 3]) instance[1] = Test([4, 5, 6]) instance[1][2] += 100 print(instance) -- Steven
On 12 July 2013 05:21, Haoyi Li
Another possible solution for the
value = expensive(b) if expensive(b) else default
problem, if you don't want a statement to assign to a temporary variable, is to use a `let` expression
// raw version value = (lambda res: res if res else default)(expensive(b))
// with a helper function `let` value = let(expensive(b))(lambda res: res if res else default)
Ahem: (lambda res=expensive(b): res if res else default)()
participants (9)
-
Andrew Barnert
-
Chris Angelico
-
Corey Sarsfield
-
David Mertz
-
Haoyi Li
-
Joao S. O. Bueno
-
Joshua Landau
-
R. Michael Weylandt
-
Steven D'Aprano