Why does this fibonacci sequence work? Can someone help me? - python-3.x
Python beginner problem
(I am a beginner programmer)
So I was making a simple Fibonacci sequence generator and I made a working version, but I'm confused about how it works. In the code (lines 8-9), the first number (0) is being made the new value of the second value (1). But then that should make all the other numbers 0 as well, but it seems like the defining process is backward. Generally, the new value is on the left of the equal sign and the old value is on the right. But then that means everything should turn to 0. But actually, every number turns to 0 if I try to re-define the variables in the regular way (b = a; c = b). Why is this? I've attached my code at the bottom.
def seq_loop():
a = 0
b = 1
for i in range(15):
print(a)
c = a + b
a = b
b = c
print(seq_loop())
Have a good look at your code. Walk through it, and write down a,b and c in each iteration (or if you know how to use a debugger, set a break point in the loop te verify your variable's values). You'll see that your thinking is not right: in your first iteration: a = b is equivalent to a = 1 and b = c is equivalent to b = 1 + 1.
I am not sure that your interpretation of assignments is correct: An assignment goes right to left. The value (of the variable) on the right side of = is assigned to the variable on the left side of =
I don't really understand what you are asking, but a good way to understand code is to simply execute it by hand with pen&paper and keep a list of all the variables in scope and their current values. So, let's do that now.
In the first line, we define and initialize the variable a to the value 0. Our variables in scope and their values are { a = 0 }.
In the second line, we define and initialize the variable b to the value 1. Our variables in scope and their values are { a = 0; b = 1 }.
In the first line of the loop, we print the current value of the variable a, which we can look up in our variable list is 0. We haven't assigned any variables, so our variables in scope are still unchanged: { a = 0; b = 1 }. And the console looks like this:
0
In the second line of the loop, we define and initialize the variable c to the result of evaluating the expression a + b. We have to dereference the two variables, i.e. look up their values in our list, and their values are 0 and 1. 0 + 1 is 1, which means we initialize c to 1. Our variables in scope and their values are { a = 0; b = 1; c = 1 }.
In the third line of the loop, we assign the variable a. The value we assign to the variable a is the current value of the variable b. So, we look at our variable list, and we see that the current value of b is 1, which means we assign 1 to a. Our variables in scope and their values are { a = 1; b = 1; c = 1 }.
In the fourth line of the loop, we assign the variable b. The value we assign to the variable b is the current value of the variable c. So, we look at our variable list, and we see that the current value of c is 1, which means we assign 1 to b. Our variables in scope and their values are { a = 1; b = 1; c = 1 }.
After the fourth line of the loop, the variable c goes out of scope. Our variables in scope and their values are now { a = 1; b = 1 }.
As you can see, we started the first iteration of the loop with { a = 1; b = 0 } but after the first iteration of the loop, we have { a = 1; b = 1 }, which is what we start the second iteration of the loop with. It is important that something has changed here, otherwise each iteration of the loop would do the same thing, and we would always get the same result.
So, let's look at the second iteration of the loop.
In the first line of the loop, we print the current value of the variable a, which we can look up in our variable list is 1. We haven't assigned any variables, so our variables in scope are still unchanged: { a = 1; b = 1 }. And the console looks like this:
0
1
In the second line of the loop, we define and initialize the variable c to the result of evaluating the expression a + b. We look up their values in our list, and their values are 1 and 1. 1 + 1 is 2, which means we initialize c to 2. Our variables in scope and their values are { a = 1; b = 1; c = 2 }.
In the third line of the loop, we assign the variable a. The value we assign to the variable a is the current value of the variable b. So, we look at our variable list, and we see that the current value of b is 1, which means we assign 1 to a. Our variables in scope and their values are { a = 1; b = 1; c = 2 }.
In the fourth line of the loop, we assign the variable b. The value we assign to the variable b is the current value of the variable c. So, we look at our variable list, and we see that the current value of c is 2, which means we assign 2 to b. Our variables in scope and their values are { a = 1; b = 2; c = 2 }.
After the fourth line of the loop, the variable c goes out of scope. Our variables in scope and their values are now { a = 1; b = 2 }.
Now for the third iteration.
In the first line of the loop, we print the current value of the variable a, which we can look up in our variable list is 1. We haven't assigned any variables, so our variables in scope are still unchanged: { a = 1; b = 2 }. And the console looks like this:
0
1
1
In the second line of the loop, we define and initialize the variable c to the result of evaluating the expression a + b. We look up their values in our list, and their values are 1 and 2. 1 + 2 is 3, which means we initialize c to 3. Our variables in scope and their values are { a = 1; b = 2; c = 3 }.
In the third line of the loop, we assign the variable a. The value we assign to the variable a is the current value of the variable b. So, we look at our variable list, and we see that the current value of b is 2, which means we assign 2 to a. Our variables in scope and their values are { a = 2; b = 2; c = 3 }.
In the fourth line of the loop, we assign the variable b. The value we assign to the variable b is the current value of the variable c. So, we look at our variable list, and we see that the current value of c is 3, which means we assign 3 to b. Our variables in scope and their values are { a = 2; b = 3; c = 3 }.
After the fourth line of the loop, the variable c goes out of scope. Our variables in scope and their values are now { a = 2; b = 3 }.
And this is the fourth iteration of the loop.
In the first line of the loop, we print the current value of the variable a, which we can look up in our variable list is 2. We haven't assigned any variables, so our variables in scope are still unchanged: { a = 2; b = 3 }. And the console looks like this:
0
1
1
2
In the second line of the loop, we define and initialize the variable c to the result of evaluating the expression a + b. We look up their values in our list, and their values are 2 and 3. 2 + 3 is 5, which means we initialize c to 5. Our variables in scope and their values are { a = 2; b = 3; c = 5 }.
In the third line of the loop, we assign the variable a. The value we assign to the variable a is the current value of the variable b. So, we look at our variable list, and we see that the current value of b is 3, which means we assign 3 to a. Our variables in scope and their values are { a = 3; b = 3; c = 5 }.
In the fourth line of the loop, we assign the variable b. The value we assign to the variable b is the current value of the variable c. So, we look at our variable list, and we see that the current value of c is 5, which means we assign 5 to b. Our variables in scope and their values are { a = 3; b = 5; c = 5 }.
After the fourth line of the loop, the variable c goes out of scope. Our variables in scope and their values are now { a = 3; b = 5 }.
Let's do one last iteration of the loop.
In the first line of the loop, we print the current value of the variable a, which we can look up in our variable list is 3. We haven't assigned any variables, so our variables in scope are still unchanged: { a = 3; b = 5 }. And the console looks like this:
0
1
1
2
3
In the second line of the loop, we define and initialize the variable c to the result of evaluating the expression a + b. We look up their values in our list, and their values are 3 and 5. 3 + 5 is 8, which means we initialize c to 8. Our variables in scope and their values are { a = 3; b = 5; c = 8 }.
In the third line of the loop, we assign the variable a. The value we assign to the variable a is the current value of the variable b. So, we look at our variable list, and we see that the current value of b is 5, which means we assign 5 to a. Our variables in scope and their values are { a = 5; b = 5; c = 8 }.
In the fourth line of the loop, we assign the variable b. The value we assign to the variable b is the current value of the variable c. So, we look at our variable list, and we see that the current value of c is 8, which means we assign 8 to b. Our variables in scope and their values are { a = 5; b = 8; c = 8 }.
After the fourth line of the loop, the variable c goes out of scope. Our variables in scope and their values are now { a = 5; b = 8 }.
I hope it is somewhat clearer now.
One thing that is very important in programming is naming. Good names should be intention-revealing. In this case, none of the names are very good: what does the name a tell you about what the intent of the programmer is? The same goes for b, c, and i. seq_loop is also not very intention-revealing, i.e. what does this function actually do? It prints the Fibonacci sequence. How can I tell from the name that it prints the Fibonacci sequence? Well, I simply can't!
So, here is the code with some better names, which should clear up some confusion:
def print_fibonacci_sequence():
previous = 0
current = 1
for _ in range(15):
print(previous)
after = previous + current
previous = current
current = after
print(print_fibonacci_sequence())
You might ask yourself "How is _ a more intention-revealing name than i?" The reason is that _ has a well-known meaning in the Python community: it is used as the name for a variable that is being ignored. Which is exactly what we are doing in this case.
Also, why after and not next? next is already defined in Python and it is considered bad style to shadow or even worse redefine Python builtins.
There are a couple of other oddities in the code. For example, the function prints the elements of the Fibonacci sequence and it doesn't return anything. And then you call the function and print the result of the call … but there is no result because the function doesn't return anything! Renaming the function to have print in its name so that it is clear that it doesn't return anything but prints it, makes that mistake more obvious:
print(print_fibonacci_sequence())
You can immediately see that you print something which prints something, which makes no sense. It should just be
print_fibonacci_sequence()
Another oddity is that the function always prints the first 15 terms of the Fibonacci sequence. Usually, you would want to let the caller decide how many terms to print. Maybe the caller only needs 3? Maybe 20? So, let's do that:
def print_fibonacci_sequence(number_of_elements):
previous = 0
current = 1
for _ in range(number_of_elements):
print(previous)
after = previous + current
previous = current
current = after
print_fibonacci_sequence(15)
Speaking of letting the caller decide what to do, what if the caller doesn't want to print the Fibonacci sequence? What if the caller wants to format it as HTML or insert it into an Excel table?
You should always separate computation from input/output. So, in this case, instead of printing the Fibonacci sequence, we will return the Fibonacci sequence, and then the caller can print it if they want to:
def fibonacci_sequence(number_of_elements):
fibonacci_sequence = []
previous = 0
current = 1
for _ in range(number_of_elements):
fibonacci_sequence.append(previous)
after = previous + current
previous = current
current = after
return fibonacci_sequence
print(fibonacci_sequence(15))
Actually, if you think about it, having the caller pass the number of terms as an argument is still somewhat restrictive. What if the caller doesn't want the first n terms, but the first terms smaller than n? In that case, they would have to compute the Fibonacci sequence first to see how many terms there are smaller than n and then ask for that number of terms of the Fibonacci sequence, which obviously defeats the purpose of having the function in the first place.
The best solution for the caller would be to produce an infinite number of terms and let the caller decide which condition to use to decide how many terms to take:
def fibonacci_sequence():
previous = 0
current = 1
while True:
yield previous
after = previous + current
previous = current
current = after
Now you can use it like this:
from itertools import islice, takewhile
first_15_terms = islice(fibonacci_sequence(), 15)
terms_less_than_100 = takewhile(lambda term: term < 100, fibonacci_sequence())
And you can decide what to do with the result. For example print it:
for term in first_15_terms:
print(term)
for term in terms_less_than_100:
print(term)
Or you can turn it into a list:
list_of_first_15_terms = list(first_15_terms)
list_of_terms_less_than_100 = list(terms_less_than_100)
And many other things.
This is a general principle in programming, software engineering, and API design: not only separate input/output from computation, but also break up the computation into separate parts for producing values, consuming values, transforming values, filtering values, representing values as strings (to be output later), parsing string representations into values (coming in from the outside), and so on.
In one sentence, we could say: separate the things that change.
Related
Python adding column with condition not working as expected
I am trying to add a column based on a condition like for i in range(len(data) - 1): a = data.loc[i, 'column1'] b = data.loc[i+1, 'column1'] if a == b: data['column2'] = 1 else: data['column2'] = 0 This shows no error and the new column has been created, however the logic does not work, the new column is filled with 0 regardless of the logic. I have checked if a == b by printing the values for a and b with a == b and the result is as I expected. I am not sure why that is? Note that the reason why I am using if statements is because my logic involves if and, else if
Inside the if statement, it should be data.loc[i,'column2'] this way it will right in the value at that location
multiply a list of numbers with 10
I have a list of numbers t. I want to multiply the numbers in the list with 10. Why does this not work?: for i in t i = i*10 Why do I have to do this?: for i in range(len(t)): t[i] = t[i]*10
Well, it doesn't work because that's no the correct syntax. You could, however, clean things up a bit with a list comprehension: t = [x * 10 for x in t]
It doesn't work that way in Python. The index variable (your i) of the for .. in construct is just a variable. At the start of each pass through the loop, Python assigns the corresponding value from the in sequence to the loop's index variable. It's as if you had a lot of copies of the loop body, and before each copy you put an assignment statement i = t[0], i = t[1], and so on. The index variable does not remember that it was assigned from the in sequence (your t). The index variable is not an equivalent name (an "alias") for the corresponding value of the in sequence. Changing the index variable does not affect the in sequence. python -c 't = [1, 2, 3] for i in t: i = 1 print t' [1, 2, 3] But you're not wrong to wonder whether it's an alias! Another language that is frequently compared with Python does work that way (quoting manual page "perlsyn"): If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. In other words, the foreach loop index variable is an implicit alias for each item in the list that you're looping over. So: perl -e '#t = (1, 2, 3); foreach $i (#t) { $i = 1; } print #t' 111
How do you modify a variable that's a value in a dictionary when calling that variable by its key?
n = 3 d = {'x':n} d['x'] += 1 print(n) When I run it, I get 3 How do I make n = 4?
You can't do this, at least, not in any simple way. The issue is very similar when you're just dealing with two variables bound to the same object. If you rebind one of them with an assignment, you will not see the new value through the other variable: a = 3 b = a a += 1 # binds a to a new integer, 4, since integers are immutable print(b) # prints 3, not 4 One exception is if you are not binding a new value to the variable, but instead modifying a mutable object in-place. For instance, if instead of 1 you has a one-element list [1], you could replace the single value without creating a new list: a = [3] b = a a[0] += 1 # doesn't rebind a, just mutates the list it points to print(b[0]) # prints 4, since b still points to the same list as a So, for your dictionary example you could take a similar approach and have n and your dictionary value be a list or other container object that you modify in-place. Alternatively, you could store the variable name "n" in your dictionary and then rather than replacing it in your other code, you could use for a lookup in the globals dict: n = 3 d = {"x": "n"} # note, the dictionary value is the string "n", not the variable n's value globals()[d["x"]] += 1 print(n) # this actually does print 4, as you wanted This is very awkward, of course, and only works when n is a global variable (you can't use the nominally equivalent call to locals in a function, as modifying the dictionary returned by locals doesn't change the local variables). I would not recommend this approach, but I wanted to show it can be done, if only badly.
You could use a class to contain the data values to enable additions. Basically you are creating a mutable object which acts as an integer. It is a work around, but lets you accomplish what you want. Note, that you probably need to override a few more Python operators to get full coverage: class MyInt(object): val = 0 def __init__(self,val): self.val = val def __iadd__(self,val): self.val = self.val + val def __repr__(self): return repr(self.val) n = MyInt(3) print(n) d = {'x':n} d['x'] += 1 print(n)
Evaluation of variable through Pass By Name
I have a doubt regarding Pass By Name Procedure test ( int c, int d) { int k = 10; c = 5; d = d + 2 ; k = c + d; print (k); } main() { k = 1; test(k,k); print (k); } I did refer to one of the earlier question on what is pass by name and how does it work and the link given in it : Pass by name parameter passing The Question i have is : will the above code print : ( 14 , 1 ) or (14, 14) Basically doubt is whether the value of k in procedure be reflected in main procedure or not. I'm preparing for an exam. This's a code snippet given in one of the question bank.
Pass by name, when you are passing a variable and not a more complex expression, behaves the same as pass by reference. Thus, your code prints 14 and 7. Note that the local variable k in your procedure test is not the same variable as the global variable k. In test, the assignments c = 5 and d = d + 2 both assign to the global k, as it was passed by name to test through both c and d. Thus, after these assignments, the global k has the value 7. The assignment k = c + d; affects the local variable k (as that is the k in scope at that time), not the global variable k (which is shadowed by the local variable), and thus the global k retains the value 7 after the assignment.
How to do this in Groovy?
Lets say that there are two variable, the value of the variable is taken from the users. That is: a=0 b=1 c=a-b For some cases i need the variable c to be always positive, is there is any method in Groovy to do this?
Couple of options, depending on want behaviour you actually want when c is negative: c = Math.abs(c) // -1 will become 1 c = Math.max(0,c) // -1 will become 0 // or it's an error condition if( c < 0 ){ tellUserToStopMessingAroundAndEnterTheCorrectValues() return }