0

I am trying to make a datalogging code, for the user to input the number and age of animals, the birth rate and their chances of surviving the generation. I have tried to use return but when I run the program, the variables remain at 0.

Here I have initiated the variables

Gen0_J=0
Gen0_A=0
Gen0_S=0
Birth_rate=0
Srate_J=0
Srate_A=0
Srate_S=0
New_generations=5

My first function

def generation_values():
    Gen0_J=int(input("How many juveniles in Generation 0? "))
    Gen0_A=int(input("How many adults in Generation 0? "))
    Gen0_S=int(input("How many seniles in Generation 0? "))
    Srate_J=float(input("What is the survival rate for juveniles? "))
    Srate_A=float(input("What is the survival rate for adults? "))
    Srate_S=float(input("What is the survival rate for seniles? "))
    Birth_rate=int(input("What is the birth rate? "))
    return Gen0_J,Gen0_A,Gen0_S,Srate_J,Srate_A,Srate_S,Birth_rate

displaying the variables

def display_values():
    print("\nThe amount of juveniles in Generation 0 is",Gen0_J)
    print("The amount of adults in Generation 0 is",Gen0_A)
    print("The amount of seniles in Generation 0 is",Gen0_S)
    print("The birth rate in Generation 0 is",Birth_rate)
    print("The survival rate for juveniles in Generation 0 is",Srate_J)
    print("The survival rate for adults in Generation 0 is",Srate_A)
    print("The survival rate for seniles in Generation 0 is",Srate_S)

generation_values()
display_values()

However, the variables stay at 0

How many juveniles in Generation 0? 5
How many adults in Generation 0? 6
How many seniles in Generation 0? 7
What is the survival rate for juveniles? 0.75
What is the survival rate for adults? 1
What is the survival rate for seniles? 0
What is the birth rate? 2

The amount of juveniles in Generation 0 is 0
The amount of adults in Generation 0 is 0
The amount of seniles in Generation 0 is 0
The birth rate in Generation 0 is 0
The survival rate for juveniles in Generation 0 is 0
The survival rate for adults in Generation 0 is 0
The survival rate for seniles in Generation 0 is 0
SuperBiasedMan
  • 9,814
  • 10
  • 45
  • 73
  • 4
    Variables created inside a function don't change the value of variables created outside the function, even if they have the same names. – Kevin Dec 02 '15 at 14:06
  • `return` doesn't place those values in the greater scope, they need to be assigned to values for that to happen. [This may be helpful](/questions/291978/short-description-of-python-scoping-rules). – SuperBiasedMan Dec 02 '15 at 14:10

3 Answers3

1

The scope of your variables is incorrect. [variables declared inside a function, inside a class, or inside a module are not accessible at a higher level in your program - here is a short description of python scoping rules that super_biased_man posted in the comments]- in this case, the variables you are assigning to in generation_values() are defined locally.

It is surely not the proper way to do this, but declaring the variables global in generation_values() will solve your problem: (defining what would be an "ideal way" of doing this is dependent on where you are at in your study of programming & would take us too far)

Gen0_J=0
Gen0_A=0
Gen0_S=0
Birth_rate=0
Srate_J=0
Srate_A=0
Srate_S=0
New_generations=5


def generation_values():

    global Gen0_J,Gen0_A,Gen0_S,Srate_J,Srate_A,Srate_S,Birth_rate

    Gen0_J=int(input("How many juveniles in Generation 0? "))
    Gen0_A=int(input("How many adults in Generation 0? "))
    Gen0_S=int(input("How many seniles in Generation 0? "))
    Srate_J=float(input("What is the survival rate for juveniles? "))
    Srate_A=float(input("What is the survival rate for adults? "))
    Srate_S=float(input("What is the survival rate for seniles? "))
    Birth_rate=int(input("What is the birth rate? "))
    return Gen0_J,Gen0_A,Gen0_S,Srate_J,Srate_A,Srate_S,Birth_rate


def display_values():
    print("\nThe amount of juveniles in Generation 0 is",Gen0_J)
    print("The amount of adults in Generation 0 is",Gen0_A)
    print("The amount of seniles in Generation 0 is",Gen0_S)
    print("The birth rate in Generation 0 is",Birth_rate)
    print("The survival rate for juveniles in Generation 0 is",Srate_J)
    print("The survival rate for adults in Generation 0 is",Srate_A)
    print("The survival rate for seniles in Generation 0 is",Srate_S)

generation_values()
display_values()

An alternate way of handling this would be to pass the variables as arguments to your functions, and return them with values assigned... But there are a lot of them and passing them around is maybe going to clutter your code.

You could also gather them in a tuple or wrap them in a class.

Community
  • 1
  • 1
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
1

The scope of your variables is not consistent.

You could do it this way:

def generation_values():
    Gen0_J=int(input("How many juveniles in Generation 0? "))
    Gen0_A=int(input("How many adults in Generation 0? "))
    Gen0_S=int(input("How many seniles in Generation 0? "))
    Srate_J=float(input("What is the survival rate for juveniles? "))
    Srate_A=float(input("What is the survival rate for adults? "))
    Srate_S=float(input("What is the survival rate for seniles? "))
    Birth_rate=int(input("What is the birth rate? "))
    return Gen0_J,Gen0_A,Gen0_S,Srate_J,Srate_A,Srate_S,Birth_rate

def display_values(Gen0_J,Gen0_A,Gen0_S,Srate_J,Srate_A,Srate_S,Birth_rate):
    print("\nThe amount of juveniles in Generation 0 is",Gen0_J)
    print("The amount of adults in Generation 0 is",Gen0_A)
    print("The amount of seniles in Generation 0 is",Gen0_S)
    print("The birth rate in Generation 0 is",Birth_rate)
    print("The survival rate for juveniles in Generation 0 is",Srate_J)
    print("The survival rate for adults in Generation 0 is",Srate_A)
    print("The survival rate for seniles in Generation 0 is",Srate_S)

Gen0_J,Gen0_A,Gen0_S,Srate_J,Srate_A,Srate_S,Birth_rate = generation_values()
display_values(Gen0_J,Gen0_A,Gen0_S,Srate_J,Srate_A,Srate_S,Birth_rate)

would be a first step.

This way, the variables in the "main" namespace is separated from the variables in the functions.

A next step to remove repetition could be not to care about the separation of the variables in the main namespace, just to treat them as a tuple:

data = generation_values()
display_values(*data)

Further steps to remove repetition and to intoduce clarity could include:

  • assemble the data in one object (namedtuple or other object)
  • ask for and outout the data in a method of the object
glglgl
  • 89,107
  • 13
  • 149
  • 217
  • Thanks so much! What does the *data do? – Uri Schmulian Dec 03 '15 at 13:29
  • It unpacks the tuple `data` so that its components are passed as distinct arguments to the called function. See [here](https://docs.python.org/2/tutorial/controlflow.html#unpacking-argument-lists). – glglgl Dec 03 '15 at 13:37
0

As others have stated, the problem is that assignments to variables inside of a function create new variables instead of assigning the values to the globals. This is why the global keyword exists.

In this case, I would consider using a class since you have a number of related state values that you manipulate together.

class GenerationData(object):

    def __init__(self, gen_number):
        self.number = gen_number
        self.birth_rate = 0
        self.num_juveniles, self.num_adults, self.num_seniles = 0, 0, 0
        self.juvenile_rate, self.adult_rate, self.senile_rate = 0.0, 0.0, 0.0

    @classmethod
    def read(cls, gen_number):
        gen = cls(gen_number)
        gen.num_juveniles = read_integer(
            'How many juveniles in Generation {}?'.format(gen_number))
        gen.num_adults = read_integer(
            'How many adults in Generation {}?'.format(gen_number))
        gen.num_seniles = read_integer(
            'How many seniles in Generation {}?'.format(gen_number))
        gen.juvenile_rate = read_float(
            'What is the survival rate for juveniles? ')
        gen.adult_rate = read_float('What is the survival rate for adults? ')
        gen.senile_rate = read_float('What is the survival rate for seniles? ')
        gen.birth_rate = read_integer('What is the birth rate? ')

    def display(self):
        print('The amount of juveniles in Generation', self.number,
              'is', self.num_juveniles)
        print('The amount of adults in Generation', self.number,
              'is', self.num_adults)
        print('The amount of seniles in Generation', self.number,
              'is', self.num_seniles)
        print('The birth rate in Generation', self.number,
              'is', self.birth_rate)
        print('The survival rate for juveniles in Generation', self.number,
              'is', self.juvenile_rate)
        print('The survival rate for adults in Generation', self.number,
              'is', self.adult_rate)
        print('The survival rate for seniles in Generation', self.number,
              'is', self.senile_rate)


def read_integer(prompt):
    return int(raw_input(prompt))


def read_float(prompt):
    return float(raw_input(prompt))


first_generation = Generation.read(0)
first_generation.display()

This will make things easier when you are manipulating the generation data since it is all bundled into a single object.

D.Shawley
  • 58,213
  • 10
  • 98
  • 113