-1

I am a bit confused over this.

I have a function. Inside that function it asks a number of questions, one is the following based on the number of gardens they have - so if they say they have 2 gardens it will ask this question twice and should add the 100 twice to the calculation:

gardens = int(input("How many gardens do you have: "))

    def gard():

    calc = 0

    gardener = input("Do you need a gardener? Y or N ")
    if gardener == "Y" or gardener == "y":
        calc = calc + 100
    else:
        calc = calc + 0

for i in range(gardens):
    gard()

How do I keep a running total outside of the function? When I put print(calc) inside the function it just displays 100 each time they say Y but doesn't add it together.


Edited to include updated code:

The eMake section (the IF statement) returns a value - but it only ever returns the first in the calculation at the end?

Also struggling to do the area section since there are numerous ws. It only stores the last value for the variable.

noGard = int(input("Enter number of gards which require cleaning: "))

#Defining variables
Calc = 0
Area = 0
emCalc = 0

#Room information
def GInfo():

    global Calc
    global Area

    gName = input("Enter gard name: ")
    noW = int(input("How many w are in the "+gName + "? "))

    #Repeats the questions for each W
    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? "))
        Area = Height * Width

    #Asks if w needs to be removed
    w = input("Does w need removing? Y or N ")
    if w == "Y" or w == "y":
        Calc = Calc + 70
    else:
        Calc = Calc + 0
    print (" ")

    #Returns the values
    return Calc
    return Area

#Calculate Sarea

#Identifying e
def e():

    global emCalc

    #eMake
    eMake = input("What make of e - HH or NN? ")
    if eMake == "HH" or "hh":
        emCalc = emCalc + 200
    elif eType == "NN" or "nn":
        emCalc = emCalc + 50
    else: print("You have entered an invalid e make")

    #Returns the values
    return emCalc

#Repeats the g information questions for each g
for i in range(noGard):
    GInfo()
# Runs the E function
e()

#Print total without VAT
total = Calc + emCalc
print(total)
print(Area)

3 Answers3

4

Your function should return the calculated value.

def gard():
   ...
   return calc

total = 0
for _ in range(gardens):
    total += gard()

print 'Total: ', total
Eugene Primako
  • 2,767
  • 9
  • 26
  • 35
2

The whole point of functions, really, is that they take parameters and return values. (Some languages, although not Python, refer to functions that don't do this as "procedures".)

That is what you need to do here: your gard function needs to return the value of calc. You probably don't want to actually do the addition inside the function itself, but if you did, you would also need to accept the current value of calc as a parameter, which you would pass in from your for loop.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
0

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.

Community
  • 1
  • 1
2rs2ts
  • 10,662
  • 10
  • 51
  • 95
  • I think the global method is probably the best option for myself. – Sarah Proctoer Dec 31 '15 at 22:20
  • @SarahProctoer It's the simplest but it's generally frowned upon; if you're being graded on this keep that in mind. – 2rs2ts Dec 31 '15 at 22:24
  • @SarahProctoer I leave it to your discretion, but in my opinion as a Python dev, using `global` is really only ok if you're writing short scripts, not maintainable programs. Object-oriented programming is very popular (Java, C++, Python, Ruby, Objective-C, Scala, C#: these are all very popular programming languages which are object-oriented) and it's good for students to learn object-oriented design. – 2rs2ts Dec 31 '15 at 22:39
  • @SarahProctoer Given that, I would say this is a good opportunity to provide two solutions to them: the one using `global` and another like Eugene's which has the function return a value, and you save it to a variable when calling it. You can then talk about the benefits and drawbacks: `global` is simpler but it is more bug-prone since someone can modify the `global` variable and it will change how the function behaves. – 2rs2ts Dec 31 '15 at 22:48
  • When you return a value which has been used within an IF statement - why does it only display the TRUE value, never the FALSE value even though it does not meet the condition? – Sarah Proctoer Dec 31 '15 at 23:03
  • @SarahProctoer Can you edit your question so I can see what you mean? – 2rs2ts Dec 31 '15 at 23:12
  • Done. Edited with my amendments since speaking. They are asked how many Gards they have. They are then asked how many w are in each gard. I then need to work out the area of each W and add all these together. The eMake section - the return is only the first condition of the IF statement, even if it does not meet that condition. – Sarah Proctoer Dec 31 '15 at 23:39
  • @SarahProctoer got it, responded in my answer. – 2rs2ts Jan 01 '16 at 00:27
  • Thank You! I have sorted it all :) Realised I had made a mistake with the IF statement - seem to always make that mistake and have to go back and correct. Used a sum to add all the Areas together. You have been a massive help. – Sarah Proctoer Jan 01 '16 at 01:13