|
|
 |
|
Title: Assignment in expression
Submitter: Sébastien Keim
(other recipes)
Last Updated: 2003/05/26
Version no: 1.1
Category:
Shortcuts
|
|
7 vote(s)
|
|
|
|
Description:
An evil equivalent for C expression: 'while x=f()'.
Source: Text Source
import sys
def set(**kw):
assert len(kw)==1
a = sys._getframe(1)
a.f_locals.update(kw)
return kw.values()[0]
A=range(10)
while set(x=A.pop()):
print x
Discussion:
This recipe is an abuse of implementation details which should only be used by debugging tools. So I strongly advise you to not use it in production code.
But it's quite fun and can still be useful for bets.
|
|
Add comment
|
|
Number of comments: 11
an alternative using list comprehensions, Andrew Dalke, 2003/07/29
Again, don't use this in real code.
>>> a = [1, 2, 9, 0]
>>> n = iter(a).next
>>> while [x for x in [n()] if x]:
... print "I have", x
...
I have 1
I have 2
I have 9
>>>
Add comment
won't work in future versions, Yair Chuchem, 2005/08/08
In future versions of python - list comprehensions won't expose the inner variable.
Add comment
Very nice., Raymond Hettinger, 2005/05/25
Add comment
Alternative, safer methods, Frank P Mora, 2005/06/22
Assignment statements and statements in general are anathema to purely functional language and Lisp programmers but are sometimes but rarely required. Assignment in an expression can also be achieved like this:
>>> ## Directly with the expressly designed function:
>>> import __main__
>>> setattr(__main__,'aaa', 300)
>>> aaa
300
>>> ## Or again with the update method and dictionaries
>>> locals().update({'aaa2':200})
>>> aaa2
200
>>> globals().update({'aaa4':500})
>>> aaa4
500
>>> __main__.__dict__.update({'aaa5':600})
>>> aaa5
600
>>> ## Or with the update method and a list of 2-tuples
>>> t= ('bbb',6)
>>> locals().update([t])
>>> bbb
6
>>> ## Or many at once
>>> k= "v1 v2 v3 v4 v5"
>>> v= "red blu grn yel brn"
>>> locals().update(zip( *[ l.split() for l in (k,v)] ))
>>> fmt= "The 5 color codes are %s, %s, %s, %s and %s"
>>> print fmt % (v1,v2,v3,v4,v5)
The 5 color codes are red, blu, grn, yel and brn
Additionally, Dr. David Mertz’s article at
http://gnosis.cx/publish/programming/charming_python_19.html
addresses “Expression Binding” and the Xoltar functional toolkit. He offers the following:
>>> list_of_list = [[1,2,3],[4,5,6],[7,8,9]]
>>> [car_x for x in list_of_list for car_x in (x[0],)]
[1, 4, 7]
>>> car_x
7
Add comment
An alternative necessary function definition and example, Frank P Mora, 2005/07/04
Sébastien is offering the utility and conciseness of the valued C code assignment and *not just* expression assignment as in the preceding comment of mine. His utility is of much greater value. It requires a function definition by necessity. Here is an alternate function definition and yet another example of the usefulness of Sébastien’s idea in a compression that calculates factorials.
def sv(vnm='', vval=None, obj=__main__):
setattr(obj, vnm, vval)
return vval
>>> import __main__
>>> fac =4
>>> [ [ sv('j', j*i) for i in range(2,fac+1) ][-1] for j in (1,) ][0]
24
>>> fac=5
>>> [ [ sv('j', j*i) for i in range(2,fac+1) ][-1] for j in (1,) ][0]
120
The advantage of the setattr function is the variable variable which allows many assignments is a single pass as in the preceding comment. It is also the standard method of expression assignment in Python.
Add comment
But then again, Frank P Mora, 2005/07/08
The list comprehension can set an initial value as in the latter part of the factorial comprehension in my last comment. After being set to 1, ‘j’ then becomes the accumulator in the calculation. If a list comprehension can set and return values as in a function can they act as accumulators?
It is completly natural for them to do so.
>>> fac =6
>>> [ [ [ j for j in (j*i,) ][0] for i in range(2,fac+1) ][-1] for j in (1,) ]
[720]
Wow! Andrew Dalke and David Mertz are my new hero’s. It seems like the awe inspiring list comprehension can do just about anything. Does Python need function definitions at all much less lambdas?
Maybe just for readability.
Add comment
Better yet, Frank P Mora, 2005/07/15
Steven Bethard pointed out in recipe 436482 that
[j for j in [1] for i in range(2,fac+1) for j in [j*i]] [-1]
is equivalent but easier to write, read and use.
Add comment
Perlishly elegant, Connelly Barnes, 2005/10/24
Add comment
set() is now a builtin, Moe Aboulkheir, 2006/02/16
so naming this function "set" is probably not the best idea
Add comment
Brittle solution, Moe Aboulkheir, 2006/03/17
this won't work if you use set() anywhere but the toplevel.
e.g:
def myfunc():
seq = range(10)
while set(var=seq.pop()):
print var
myfunc()
-> NameError: global name 'var' is not defined
the behaviour is also different if the loop variable is already bound:
def myfunc(var='x')
seq = range(10)
while set(var=seq.pop()):
print var
myfunc()
-> equivalent to "while seq.pop(): print 'x'"
Add comment
Another solution., Aristotelis Mikropoulos, 2006/08/14
class DataHolder( object ) :
"""A simple data holder.
"""
def __init__( Self , Value = None ) :
"""The constructor.
"""
Self.Value = Value
def Get( Self ) :
"""Returns the value.
"""
return Self.Value
def Set( Self , Value ) :
"""Sets the value, as well as
returns it.
"""
Self.Value = Value
return Self.Value
Add comment
|
|
|
|
|
 |
|