I have a simple function containing a loop that calculates how money grows per year with interest, which got me thinking about scope and variables in Python.
def invest(amount, rate, years):
for i in range(years):
amount = amount + amount*rate
print(f"year {i+1}: ${amount:.2f}")
invest(100, 0.05, 4)
The output:
year 1: $105.00
year 2: $110.25
year 3: $115.76
year 4: $121.55
I know it works, but usually I would create the 'amount' variable above the for loop to ensure that after each iteration, that variable will get updated. Since I didn't do that this time, I assume that this variable gets created globally so that happens automatically.
Are my assumptions correct? Thank you
If it was global then you would be able to access it outside the function. The scope of the variable is limited to that specific function.
You can also create another intermediate variable above the loop but it wouldn't change much about the function- you don't need the original value of amount in your function so for your purposes- using that variable and updating it directly in your loop is fine.
The answer above already satisfy what you asked, but I think the following link might be good for your learning, as it was good for mine. In Python Tutor you can put your code and visualize what happens inside the global scope, functions' scopes, etc. Hope this can help you!
Related
for i in rates:
if input_currency == currency:
if output_currency in rates[currency]:
pass
else:
for i in rates:
Is it generally a bad thing to use the same variable i again within a for loop? Even if I loop through the same data structure again? PyCharm just tells me it's been used already, but it still works.
It's not wrong. But it's dangerous if you don't know what you are doing. For example, you might have problems if you want to use i inside the outer loop:
rates = [1,2,3,4,5]
for i in rates:
for i in rates:
pass
print(i) # This always prints 5
This may confuse you if you're not familiar with Python. In C, for example, a variable defined inside the inner loop is different from the one that is defined in the outer loop (i.e., you can reuse the same name for different variables).
In one of my programs ,
def travel():
travel.frate=[]
travel.s=0
in this,the teacher told me to use module name to declare global variables.
like travel.frate and travel.s=0. She didn't tell why it is so.could some one please explain why we are using this?? She told me to use this because global variables couldn't be declared in my computer.
travel.s gives you a variable with identical scope to the function itself -- this is equivalent to a static variable in C. This means that the value of travel.s isn't deleted from memory as soon as travel() exits, as would be the case for s defined within the travel function.
To state it a little differently, the value persists across multiple calls to the function, unlike a local variable which has a new value assigned each time.
By the way -- Python does have module-scoped variables (these are what the "global" keyword refers to in Python); your teacher was thus somewhat inaccurate/misleading in the guidance given.
One could use a module-scoped variable like so:
s = 0
def travel():
global s # this lets the travel function update the value
s = s + 1 # ...so that the change here persists across multiple calls
All that said -- use of module-level variables is often a bad practice and a code smell in Python; hopefully, you'll be learning object-oriented design later in your course.
I am very new to Python and as an exercise I tried solving a basic finance exercise using code. My objective is to get a dictionary of spot rates and then a dictionary of discount rates calculated from those. I had thought to something like this:
discountrates={}
def discountrates(n):
spotrates={}
for x in range(1,n+1):
spotrates['s'+str(x)]=float(input('What is s'+str(x)+'? (not in percentage)'))
for y in range(1,n+1):
discountrates['d(0,'+str(y)+')']= 1/((1+float(spotrates['s'+str(y)]))**y)
for key, value in discountrates.items():
print (key, value)
Now the problem is that dictionary items cannot be accessed in a function. When I looked in your forum, I found solutions for unpacking the dictionary but that does not work in my case because I need to access a specific element of the dictionary, whose name cannot be fully specified (as I have seen in the Python manual) because it's part of a loop, in order for the formula to work without having to manually insert anything else. I used a dictionary in the first place to create names that were automatically generated but now I can't seem to get the information out of it.
What is the best solution?
Thanks in advance for the help. It's been driving me crazy.
It's because you called your global variable discountratesdict not discountrates (which is the name of your function).
I suggest you don"t name your dictionary like your function since the later will overwrite the former. In line 1 you say discountrates is an empty dict, in line 2 you say discountrates is a function object. You need to give them different names in python if they are on the same scope.
Furthermore why do you need discountrates to be global? would you like to keep old rates if n is smaller than a previous n? For performance I suggest you combine the two loops. Besides that there is no reason why the second loop can't read for x ... as well since zou don't use x anymore anyway. As a further hint, if you come to the conclusion, that a global is the only way it might help to add global discountratesdict, so it is easier to spot that a global is intended here, even though this is not necessary in your particular case since the []-operator needs an object and thus it already refers to your global.
Putting all this together yields:
discountratedict={}
def discountrates(n):
global discountratedict
spotrates={}
for x in range(1,n+1):
spotrates['s'+str(x)]=float(input('What is s'+str(x)+'? (not in percentage)'))
discountratedict['d(0,'+str(x)+')']= 1/((1+float(spotrates['s'+str(x)]))**x)
for key, value in discountratedict.items():
print (key, value)
sorry if this is an obvious question, but I am relatively new to python and am completely stumped at the moment. I am having difficulty getting my variables to work the way I want them too in a program I am working on.
Here is an example I quickly made to showcase my problem:
life = 200
def example(dudeHP):
dudeHP = dudeHP - 75
print (dudeHP)
example(life)
print (life) #output is 200, but I want it to be 125
As you can see, I am trying to get the value of the global variable "life" to change inside the def example codeblock with dudeHP (which would be a local variable if I am not mistaken?)
Is this viable? Is there a better way to accomplish this? Or am I doing it all wrong? Thankyou in advance :)
Well, first of all, you'll probably want to write an class or something to organize all this at some point. Modifying global variables from within functions or methods is usually considered a bad idea.
What you might want to try is this:
life = 200
def example(x):
return x - 75
life = example(life)
Of course in this case the operation of subtraction is so trivial that you don't need to encapsulate it in a function.
BTW, the question is not Python3 specific unless a newcomer gets stumped by the title. It is a general Python language question.
You have to understand the scope and the nature of the variables in Python. Variables are just names to hold certain values and their life is within the scope of the block they are defined it, although the inner scope variable can access the variable from the outer scope. The function you have defined has its own scope and it's own stack to maintain and you are passing a copy of the variable to that function.
The best way to deal with this is return value from the function as pointed out in another answer.
Having said that, if you really want to access variable in a global manner, you could do like this.
a = 200
def example(b):
global a
a = a - 25
example(a)
print a
But this is frowned upon and not a good style. There is also a trick which you are use, but that goes beyond the beginner level and it goes like this.
a = [200]
def example(a):
a[0] = a[0] - 25
example(a)
print a[0]
You can easily make mistakes you if adopt this way,
But the correct way to go about this is still:
a = 200
def example(b):
return b - 25
print example(a)
Further to Ned Batchelders and Kristoff's hints and suggestions to use a class, this is a way you could do that:
class Dude:
def __init__(self, hp=200):
self.hp = hp
def eat(self):
self.hp = self.hp + 25
def example(dude):
dude.hp -= 75
hero = Dude()
example(hero)
hero.eat()
print(hero.hp) # 150
Unless you have a good reason why example should be a stand-alone function, you should make it a method of Dude like eat, since example clearly acts on and in a sense belongs to an object of the class Dude.
In your function, the name dudeHP is local to the function. When you change it, you are only changing the local name, you cannot affect the value of the name passed in.
You can either make the integer be an element of a container that you pass in, so that you can change the container, or you can return the value from the function.
Since dudehp is having local scope in that function it doesn't have life outside that function. So, using dudehp to update life is illegal you can do this by using a global keyword or returing the value as others have mentioned... hope this explanation is useful and any corrections to this will be accepted.
I'm currently developing some things in Python and I have a question about variables scope.
This is the code:
a = None
anything = False
if anything:
a = 1
else:
a = 2
print a # prints 2
If I remove the first line (a = None) the code still works as before. However in this case I'd be declaring the variable inside an "if" block, and regarding other languages like Java, that variable would only be visible inside the "if".
How exactly variable scoping works in Python and what's the good way to program in cases like this?
Thanks!
As a rule of thumb, scopes are created in three places:
File-scope - otherwise known as module scope
Class-scope - created inside class blocks
Function-scope - created inside def blocks
(There are a few exceptions to these.)
Assigning to a name reserves it in the scope namespace, marked as unbound until reaching the first assignment. So for a mental model, you are assigning values to names in a scope.
I believe that Python uses function scope for local variables. That is, in any given function, if you assign a value to a local variable, it will be available from that moment onwards within that function until it returns. Therefore, since both branches of your code are guaranteed to assign to a, there is no need to assign None to a initially.
Note that when you can also access variables declared in outer functions -- in other words, Python has closures.
def adder(first):
def add(second):
return first + second
return add
This defines a function called adder. When called with an argument first, it will return a function that adds whatever argument it receives to first and return that value. For instance:
add_two = adder(2)
add_three = adder(3)
add_two(4) # = 6
add_three(4) # = 7
However, although you can read the value from the outer function, you can't change it (unlike in many other languages). For instance, imagine trying to implement an accumulator. You might write code like so:
def accumulator():
total = 0
def add(number):
total += number
return total
return add
Unfortunately, trying to use this code results in an error message:
UnboundLocalError: local variable 'total' referenced before assignment
This is because the line total += number tries to change the value of total, which cannot be done in this way in Python.
There is no problem assigning the variable in the if block.
In this case it is being assigned on both branches, so you can see it will definitely be defined when you come to print it.
If one of the branches did not assign to a then a NameError exception would be raise when you try to print it after that branch
Python doesn't need variables to be declared initially, so you can declare and define at arbitrary points. And yes, the scope is function scope, so it will be visible outside the if.
i'm quite a beginner programmer, but for what i know, in python private variables don't exist. see private variables in the python documentation for a detailed discussion.
useful informations can also be found in the section "scopes and namespaces" on the same page.
personally, i write code like the one you posted pretty much every day, especially when the condition relies in getting input from the user, for example
if len(sys.argv)==2:
f = open(sys.argv[1], 'r')
else:
print ('provide input file')
i do declare variables before using them for structured types, for example i declare an empty list before appending its items within a loop.
hope it helps.