Variable assignment in expressions - python

Here is my code to generate values in the fibonnacci sequence below 10,000,000.
3 fibs = [1,1]
4 while((x = fibs[-1] + fibs[-2]) <= 10000000):
5 fibs.append(x)
I attempted to do C-style assignment of x in the while loop's condition. Unfortunately, python told me that it's a syntax error. What is the simplest solution?

In Python, assignment is not an expression, and therefore has no value.
The simplest solution is to do the assignment in the first part of the loop:
fibs=[1,1]
while fibs[-1] <= 10000000:
fibs.append(fibs[-1] + fibs[-2])

Basically:
fibs = [1]
x = 1
while(x <= 10000000):
fibs.append(x)
# It is not possible for "fibs" not to have
# at least two elements by now
x = fibs[-1] + fibs[-2]
(It was, in fact, one of the design goals of Python to avoid mixing expressions and assignments like C — that's why there's no x++, x--, which is also a semi-FAQ.)

The reason for not allowing assignment in Python expressions is a common, hard-to-find bug in those other languages, caused by this construct.
Please check
http://effbot.org/pyfaq/why-can-t-i-use-an-assignment-in-an-expression.htm

from functools import partial
from itertools import imap, islice, takewhile
import operator
fibs = [1, 1]
for x in takewhile(partial(operator.ge, 10000000),
imap(operator.add, fibs, islice(fibs, 1, None))):
fibs.append(x)
Oh wait, you said "simplest"? Nevermind then.

Related

for loop list incrementation

In order to find multiples of 3 under 1000, I used this method:
a=[]
import itertools
for x in itertools.count():
while x<1000:
if x%3==0:
a.append[x]
print(a)
I'm a beginner, please help me find the error.
Why not simply
a = list(range(0, 1000, 3))
or even
a = range(0, 1000, 3)
in Python 2?
Are you coding in Python 3 ?
You are missing indentation mostly and usage of function depends on the version of Python you are using and also there are different solutions to how you can handle the iterations , which may differ to your style. I also want to point out that append method needs parentheses instead of brackets.
However i tried not to modify your code much.
You can check it on the online editor below.
https://repl.it/#Umbreon1/SpiffyAshamedPdf
import itertools
a=[]
upperLimit=1000
for x in itertools.islice(itertools.count(0),upperLimit + 1):
if x%3 == 0:
a.append(x)
print(a)

How to stop short circuiting in Python?

Python short circuits the logical operators.
for eg:
if False and Condition2:
#condition2 won't even be checked because the first condition is already false.
Is there a way to stop this behavior. I want it to check both the conditions and then perform the and operation(as done in c, c++ etc). It's useful when we are performing some operation along with the condition. e.g.:
if a < p.pop() and b < p.pop():
One way can be checking the conditions before and then comparing the Boolean values. But that would be wastage of memory.
if all([a < p.pop(), b < p.pop()])
This creates a list, which will be evaluated in its entirety, and then uses all to confirm that both values are truthy. But this is somewhat obscure and I'd rather suggest you write plain, easy to understand code:
a_within_limit = a < p.pop()
b_within_limit = b < p.pop()
if a_within_limit and b_within_limit:
If the conditions are booleans, as they are in your example, you could use & instead:
>>> a, b, p = 1, 1, [0, 0]
>>> (a < p.pop()) & (b < p.pop())
False
>>> p
[]
You can use the all() and any() built-in functions to somehow emulate the and and or operators. Both take an iterable of boolean-likes values as parameter. If you give it a literal tuple or list, all members will be fully evaluated:
# all emulates the and operator
if all((False, Condition2)):
do_stuff()
# any emulates the or operator
if any((False, Condition2)):
do_stuff()
Short answer: No, you cannot stop it to do this.
For example:
av = p.pop()
bv = p.pop()
if a < av and b < bv:
pass
Or:
av, bv = p.pop(), p.pop()
if a < av and b < bv:
pass
Also, there is no waste of memory in these examples. In Python, almost everything is done by reference. The value object being popped already exists somewhere. Even the scalars like strings, ints, etc are objects (some of them are slightly optimized). The only memory changes here are (1) the creation of a new variable that refers to the same existing object, and (2) removal of the record in the dict at the same time (which referred to that object before popping). They are of the similar scale.

How to decrement a variable while printing in Python?

Some if and else's can be rewritten1 and shortened2 (codegolf-style) likewise, because booleans can act as integers in Python. For example if a<b:return a can be rewritten3 as return("",a)[a<b].
In this case (I simplified the condition for readability),
if a<b: print(a)
can be rewritten as both of the following:
print(("",a)[a<b])
(print(""),print(a))[a<b]
(if we ignore newlines, else end="" can be used).
I would like to decrement a variable n (the whole thing is in a while loop with n in its condition) when a<b is true on top of everything, eg.
if a<b:
print(a)
n-=1
while using the syntax trick above.
In C, (n/n--)-1 is not only equal to 0, but also substracts 1 from n. In Python, I haven't found a way to do this. Some invalid syntaxes I tried:
print(("",a+(n/n--)-1)[a<b])
(print(""),(print(a);n-=1))[a<b]
How to decrement the variable (and print a) when the condition is true using this "trick"?
1,2,3: these statements aren't always true
Python isn't C. For one thing, Python doesn't have a decrement operator, so print(n--) won't work. For another, assignments in Python are statements, not expressions, so print(n-=1) won't work.
If you truly wanted your print statement to have side effects, it could invoke a function:
def decrement():
global n
n -= 1
return n
print(decrement())
But don't. No one will expect that your print statement has side-effects, so everyone will be surprised when commenting out your print statement changes the program's result.
EDIT: I just noticed that this is a code golf question. In that case, my stylistic advice isn't really valid. Everyone expects golfed code to be weird.
Ps. If your goal is to change if statements into expressions, then play with and and or, which short circuit. For example:
a<b and (print(a), decrement())
Or use if ... else expressions
(print(a),decrement()) if a<b else None
n = 10
print(n // (n := n-1) - 1)
# (x := y) is the equivalent of x = y
#but you can use it inside expressions
#and it returns the new value of x
# finally a C simple assignment
a = (b := 1)
print(a, b)
gives
0
1 1

applying for loop such that counters are multiplied rather than being added in python

hello I am relatively new to python! Is there a way to do this using for loops in python?
This is a java implementation of something i want to do in python
for (i=1;i<20; i*= 2)
{System.out.println(i);}
Solution in while loop in python`
while i<20:
print i
i*=2
I cannot figure out a way to do this using for loops. Implemented it using while loop obviously, but still curious to know whether there is a method to do so or not
There are lots of ways to do this, e.g.
for i in range(5):
i = 2 ** i
print i
or using generators
from itertools import count, takewhile
def powers_of_two():
for i in count():
yield 2 ** i
for i in takewhile(lambda x: x < 20, powers_of_two()):
print i
But in the end, it depends on your use case what version gives the clearest and most readbale code. In most cases, you would probably just use a while-loop, since it's simple and does the job.
You think of for loops like they would be in other languages, like C, C++, Java, JavaScript etc.
Python for loops are different; they work on iterables, and you always have to read them like:
for element in iterable
instead of the C'ish
for(start_condition; continue_condition; step_statement)
Hence, you would need iterable to generate your products.
I like readability, so here's how I'd do it:
for a in (2**i for i in range(20)):
print a
But that mainly works because we mathematically know that the i'th element of your sequence is going to be 2**i.
There is not a real way to do this in Python. If you wanted to mimic the logic of that for loop exactly, then a manual while loop would definitely be the way to go.
Otherwise, in Python, you would try to find a generator or generator expression that produces the values of i. Depending on the complexity of your post loop expression, this may require an actual function.
In your case, it’s a bit simpler because the numbers you are looking for are the following:
1 = 2 ** 0
2 = 2 ** 1
4 = 2 ** 2
8 = 2 ** 3
...
So you can generate the numbers using a generator expression (2 ** k for k in range(x)). The problem here is that you would need to specify a value x which happens to be math.floor(math.log2(20)) + 1 (because you are looking for the largest number k for which 2 ** k < 20 is true).
So the full expression would be this:
for i in (2 ** k for k in range(math.floor(math.log2(20)) + 1)):
print(i)
… which is a bit messy, so if you don’t necessarily need the i to be those values, you could move it inside the loop body:
for k in range(math.floor(math.log2(20)) + 1):
i = 2 ** k
print(i)
But this still only fits your purpose. If you wanted a “real” C-for loop expression, you could write a generator function:
def classicForLoop (init, stop, step):
i = init
while i < stop:
yield i
i = step(i)
Used like this:
for i in classicForLoop(1, 20, lambda x: x * 2):
print(i)
Of course, you could also modify the generator function to take lambdas as the first and second parameter, but it’s a bit simpler like this.
Use range() function to define iteration length.You can directly use print() than system.out.println
Alexander mentioned it and re-iterating
for i in range(1,20):print(i*2)
You can also consider while loop here-
i=0
while (i<20):
print(2**i)
i=i+1
Remember indentation in python

Set variables in python list comprehension

If I have 2 or 3 of the same calculations done within a generator for each loop, is there a way to just set them as a variable?
A quick example would be like this:
#Normal
[len( i ) for i in list if len( i ) > 1]
#Set variable
[x for i in list if x > 1; x = len( i )]
Before anyone says len( i ) would be so fast the difference would be negligible, I also mean for other calculations, using len just made it easier to read.
Also, if there is a way, how would you set multiple variables?
Apologies if it's been asked before, but I've searched around and not found anything.
One way to get around the expensive operation is to nest a generator in a list comprehension that simply acts as a filter, for example
def foo(x): # assume this function is expensive
return 2*x
>>> [j for j in (foo(i) for i in range(6)) if j > 4]
# ^ only called once per element
[6, 8, 10]
Using analogous functions and variables to your example, you'd have
[x for x in (len(i) for i in list) if x > 1]
Most implementations of Python do not, as you correctly surmise, have common sub-expression optimization, so your first expression would indeed call len(x) twice per iteration. So why not just have two comprehensions:
a = [len(x) for x in list]
b = [x for x in a if x > 1]
That make two passes, but only one call of len() per. If the function were an expensive one, that's probably a win. I'd have to time this to be sure.
Cyber's nested version is essentially the same thing.
using itertools.imap in python2 will be an efficient way to do what you need and most likely outperform a generator expression:
[x for x in imap(len, lst) if x > 4]

Categories