Functions, in the strictest sense, do not have state. When writing functional programs, one typically aims to keep their functions pure, meaning that the result of the function does not depend on anything but its inputs and does not cause observable side effects.
But Python is not a purely functional language. It is an object-oriented procedural language which models functions as objects, and objects can be stateful. So you can do what you're aiming to, if you don't take the word "function" too literally.
The Right Thing™
Create a class which models your data and the operations on it:
>>> class F(object):
... def __init__(self):
... self.x = 0
... def f(self):
... self.x += 1
... return self.x
...
>>> my_f = F()
>>> my_f.f()
1
>>> my_f.f()
2
Fun and naughty ways
Add state to the function object, taking advantage of the fact that function bodies aren't executed until the function is called:
>>> def f():
... f.x += 1
... return f.x
...
>>> f.x = 0
>>> f()
1
>>> f()
2
If you want to do this transparently (that is, make it so that you don't have to add this state to the function right after defining it) you can close over the state by having a function create a function:
>>> def g():
... def func():
... func.x += 1
... return func.x
... func.x = 0
... return func
...
>>> f = g()
>>> f()
1
>>> f()
2
To take it a step further, create a decorator so you don't have to do any assignments after defining the function at all:
>>> def with_x(func):
... func.x = 0
... return func
...
>>> @with_x
... def f():
... f.x += 1
... return f.x
...
>>> f()
1
>>> f()
2
Or you can just use global
to let a function refer to something outside of its local scope, not taking advantage of the fact that functions are objects:
>>> x = 0
>>> def f():
... global x
... x += 1
... return x
...
>>> f()
1
>>> f()
2
>>> x
2
Updates for your edit
Since you went with global
I'll first refer you to a good question that explains global
. Using global variables in a function other than the one that created them
Now, as for your particular problems:
The eMake section (the IF statement) returns a value - but it only ever returns the first in the calculation at the end?
Sure, there are a couple problems here and one of them is definitely a common one for beginners. or
takes higher precedence than ==
so your condition parses like this:
if (eMake == "HH") or ("hh"):
This gets people all the time. In Python, if a value isn't a boolean and you put it in a conditional statement, it gets evaluated as a boolean using a series of truthiness rules. In this case a non-empty string is considered True
so you are basically saying if (eMake == "HH") or True
.
To fix this, fix the right-hand side of the condition:
if (eMake == "HH") or (eMake == "hh"):
By the way, you probably meant elif (eMake == "NN") or (eMake == "nn"):
instead of elif eType == "NN" or "nn":
because you never defined eType
(and for the reason above, too.) If you type nn
there you'll get an exception.
Also struggling to do the area section since there are numerous ws. It only stores the last value for the variable.
This is because you repeatedly assign to the same variable with Area = Height * Width
. Since Area
is global
, it's the same variable every time you call GInfo()
. If it wasn't global
it would be a new variable every time you called the function, but then you would need to return it and assign the return value to a variable in order to save the value. Otherwise it would disappear since it was never assigned to anything.
Now, I don't know what you are trying to do with the areas you're calculating. Do you want to keep them separate or sum them together?
If you want to keep them separate, you'll need to use a data structure. In this case, you'd definitely want to use a list. Using the append()
method of lists, you can add an item to the list. So it would look something like this:
areas = [] # empty list
def GInfo():
global areas
# the stuff before the loop
for i in range(noW):
Height = float(input("What is the w height of in metres? "))
Width = float(input("What is the w width in metres? "))
areas.append(Height * Width)
# the stuff after the loop
If you want to sum them together, just make sure you add each individual area calculation to the previous result, just like you did with Calc
:
Area += Height * Width
One more thing: your GInfo()
function is only returning Calc
and not Area
as well. Functions can only return one value. In the mathematical sense, a function is a many-to-one mapping between two sets. So in Python, a function ends at the return
statement. Nothing else gets executed after that.
In order to get both the value of Calc
as well as the value of Area
from the return value of GInfo()
, you will have to return a data structure. Usually this would be a tuple.
return (Calc, Area)
But your code doesn't assign the return value of GInfo()
to anything. Instead, it uses the global
declaration to change the value of the global variables. So there shouldn't be an issue here.