owenbradstreet
owenbradstreet

Reputation: 148

Setting variables in a function and importing them

I'm writing an adventure game, and I'm writing functions in different files, such as the saveGame function and read function. There are 4 main files, all interconnected. The main one is agMain.py. My issue is that I've imported one of my other files agRead.py, and call the function within that called read(). Here is the data for the agRead.py:

import os
import operator
import sys
import agSave
import agCreation
def read():
    while True:
        try:
            file = open("agData.txt", "r")
        except:
            exec(open("agCreation.py").read())
            break
        break
    file = open("agData.txt", "r")
    data = file.readlines(0)
    encrypFName = data[0]
    encrypSName = data[1]
    encrypAge = data[2]
    encrypGender = data[3]
    encrypHealth = data[4]
    encrypMaxHealth = data[5]
    encrypArmour = data[6]
    encrypMaxArmour = data[7]
    encrypHealthPotions = data[8]
    encrypExp = data[9]
    encrypMaxExp = data[10]
    encrypLevel = data[11]
    encrypGold = data[12]
    encrypMaxGold = data[13]
    encrypPowerLevel = data[14]
    encrypMaxPowerExp = data[15]
    encrypPowerExp = data[16]
    encrypStage = data[17]
    fName = encrypFName.strip()
    sName = encrypSName.strip()
    age = encrypAge.strip()
    gender = encrypGender.strip()
    health = encrypHealth.strip()
    maxHealth = encrypMaxHealth.strip()
    armour = encrypArmour.strip()
    maxArmour = encrypArmour.strip()
    healthPotions = encrypHealthPotions.strip()
    exp = encrypExp.strip()
    maxExp = encrypMaxExp.strip()
    level = encrypLevel.strip()
    gold = encrypGold.strip()
    maxGold = encrypMaxGold.strip()
    powerLevel = encrypPowerLevel.strip()
    maxPowerExp = encrypMaxPowerExp.strip()
    powerExp = encrypPowerExp.strip()
    stage = encrypStage.strip()

As you can see, it sets variables such as stage and level. My agMain files however:

import os
import operator
import sys
import agSave
import agRead
while True:
    agRead.read()
    if (stage == 1):
        exec(open("agStage1.py").read())
    elif (stage == 2):
        exec(open("agStage2.py").read())
    elif (stage == 3):
        exec(open("agStage3.py").read())
    elif (stage == 4):
        exec(open("agStage4.py").read())
    elif (stage == 5):
        exec(open("agStage5.py").read())
    elif (stage == 6):
        exec(open("agStage6.py").read())
    elif (stage == 7):
        exec(open("agStage7.py").read())
    elif (stage == 8):
        exec(open("ageStage8.py").read())
    elif (stage == 9):
        exec(open("agStage9.py").read())
    elif (stage == 10):
        exec(open("agStage10.py").read())
    elif (stage > 10):
        for i in range(100):
            print("Game over!")
        print("****************")
        print("Well done, you have completed the game!")
        exit()
    else:
        print("An error has occured.")
        continue

As you can see here, it uses the stage when it from the function in the code. But it can't. If I run this, it says stage is not defined, like I hadn't run the function. Is it possible to set variables in a function, use the function, and use the variables in creates in a different file?

EDIT

At the time I made this, I had no knowledge of classes, so I apologise. Everyone who is having a similar problem (sharing variables between functions) just make a class with the functions you want as methods. It saves a lot of hassle!

Upvotes: 1

Views: 57

Answers (6)

holdenweb
holdenweb

Reputation: 37003

You need to understand a little more about scoping. Inside a function, names that are bound by an assignment statement are created in the local namespace of the function call. This namespace is created when the function call is made and initialised with the values of the parameters bound to their names. When the function returns (or raises an exception) the namespace is deleted, and the names are no longer available.

Since you want to read lots of different values, consider creating an instance of a class. Instances also have a namespace, and names bound in that namespace will continue to be available until deleted or until the object is garbage collected.

After @Merlin published his helpful answer I decided to update this answer to include a data-driven version, reproduced below (but not tested). Thinking about this might lead you to a function that can create/initialise several different types of object.

Since execution speed is unlikely to be an issue I preferred an approach that was more generalised.

class Conf(object):
    pass

def read():
    while True:
        try:
            file = open("agData.txt", "r")
        except:
            exec(open("agCreation.py").read())
            break
        break
    file = open("agData.txt", "r")

    conf = Conf()

    names = ["fName", "sName", "age", "gender", "health", "maxHealth",
         "armour", "maxArmour", "healthPotions", "exp", "maxExp",
         "level", "gold", "maxGold", "powerLevel", "maxPowerExp",
         "powerExp", "stage"]
    for name in names:
        setattr(conf, name, next(file).strip()
    return conf

Upvotes: 1

Merlin
Merlin

Reputation: 25639

By using chaining, you can reduce the number of lines used and increase readability.

  class Conf(object):
        pass

def read():
    while True:
        try:
            file = open("agData.txt", "r")
        except:
            exec(open("agCreation.py").read())
            break
        break
    file = open("agData.txt", "r")
    data = file.readlines(0)

    conf = Conf()

    conf.fName     = data[0].strip()
    conf.sName     = data[1].strip()
    conf.age       = data[2].strip()
    conf.gender    = data[3].strip()
    conf.health    = data[4].strip()
    conf.maxHealth = data[5].strip()
    conf.armour    = data[6].strip()
    conf.maxArmour = data[7].strip()
    conf.healthPotions = data[8].strip()
    conf.exp       = data[9].strip()
    conf.maxExp    = data[10].strip()
    conf.level     = data[11].strip()
    conf.gold      = data[12].strip()
    conf.maxGold   = data[13].strip()
    conf.powerLevel = data[14].strip()
    conf.maxPowerExp =data[15].strip()
    conf.powerExp  = data[16].strip()
    conf.stage     = data[17].strip()
    return conf

Upvotes: 1

owenbradstreet
owenbradstreet

Reputation: 148

Okay, so I have worked this out. Thanks to everyone who answered, but holdenweb and nightcrawler especially. I have created a class in the agRead.py, and put all of the variables as a part of that class, before returning the class. Here is my agRead.py now:

import os
import operator
import sys
import agSave
import agCreation
class Conf(object):
    pass

# READ FUNCTION
def read():
    try:
        open("agData.txt", "r")
    except:
        exec(open("agCreation.py").read())
    file = open("agData.txt", "r")
    data = file.readlines(0)
    encrypFName = data[0]
    encrypSName = data[1]
    encrypAge = data[2]
    encrypGender = data[3]
    encrypHealth = data[4]
    encrypMaxHealth = data[5]
    encrypArmour = data[6]
    encrypMaxArmour = data[7]
    encrypHealthPotions = data[8]
    encrypExp = data[9]
    encrypMaxExp = data[10]
    encrypLevel = data[11]
    encrypGold = data[12]
    encrypMaxGold = data[13]
    encrypPowerLevel = data[14]
    encrypMaxPowerExp = data[15]
    encrypPowerExp = data[16]
    encrypStage = data[17]

    conf = Conf()

    conf.fName = encrypFName.strip()
    conf.sName = encrypSName.strip()
    conf.age = encrypAge.strip()
    conf.gender = encrypGender.strip()
    conf.health = encrypHealth.strip()
    conf.maxHealth = encrypMaxHealth.strip()
    conf.armour = encrypArmour.strip()
    conf.maxArmour = encrypArmour.strip()
    conf.healthPotions = encrypHealthPotions.strip()
    conf.exp = encrypExp.strip()
    conf.maxExp = encrypMaxExp.strip()
    conf.level = encrypLevel.strip()
    conf.gold = encrypGold.strip()
    conf.maxGold = encrypMaxGold.strip()
    conf.powerLevel = encrypPowerLevel.strip()
    conf.maxPowerExp = encrypMaxPowerExp.strip()
    conf.powerExp = encrypPowerExp.strip()
    conf.stage = encrypStage.strip()
    return conf

and my agMain.py:

 # Main
    # Will open a stage depending on the stage the user is at.
    import os
    import operator
    import sys
    import agSave
    import agRead
    #Read the file
    while True:
        agRead.read()
        if (conf.stage == 1):
            exec(open("agStage1.py").read())
        elif (conf.stage == 2):
            exec(open("agStage2.py").read())
        elif (conf.stage == 3):
            exec(open("agStage3.py").read())
        elif (conf.stage == 4):
            exec(open("agStage4.py").read())
        elif (conf.stage == 5):
            exec(open("agStage5.py").read())
        elif (conf.stage == 6):
            exec(open("agStage6.py").read())
        elif (conf.stage == 7):
            exec(open("agStage7.py").read())
        elif (conf.stage == 8):
            exec(open("ageStage8.py").read())
        elif (conf.stage == 9):
            exec(open("agStage9.py").read())
        elif (conf.stage == 10):
            exec(open("agStage10.py").read())
        elif (conf.stage > 10):
            for i in range(100):
                print("Game over!")
            print("****************")
            print("Well done, you have completed the game!")
            exit()
        else:
            print("An error has occured.")
            continue

And this works perfectly, thank you everyone! This is an amazing community, and I hope to become a real member of it! Thanks again!

Upvotes: 0

Andriy Ivaneyko
Andriy Ivaneyko

Reputation: 22021

Yes it's possible, but variable would be available only after function execution:

### file agRead.py ###
def read():
    # some code there
    read.my_super_var = 'value'

### file agMain.py ###
import agRead

agRead.read()
print(agRead.read.my_super_var) # value

Upvotes: 0

totoro
totoro

Reputation: 2456

The variables are only visible from inside read.

Contain the variables you want to use by doing something like this.

agRead.py

class Conf(object):
    pass


def read():
    while True:
        try:
            file = open("agData.txt", "r")
        except:
            exec(open("agCreation.py").read())
            break
        break
    file = open("agData.txt", "r")
    data = file.readlines(0)
    encrypFName = data[0]
    encrypSName = data[1]
    encrypAge = data[2]
    encrypGender = data[3]
    encrypHealth = data[4]
    encrypMaxHealth = data[5]
    encrypArmour = data[6]
    encrypMaxArmour = data[7]
    encrypHealthPotions = data[8]
    encrypExp = data[9]
    encrypMaxExp = data[10]
    encrypLevel = data[11]
    encrypGold = data[12]
    encrypMaxGold = data[13]
    encrypPowerLevel = data[14]
    encrypMaxPowerExp = data[15]
    encrypPowerExp = data[16]
    encrypStage = data[17]

    conf = Conf()

    conf.fName = encrypFName.strip()
    conf.sName = encrypSName.strip()
    conf.age = encrypAge.strip()
    conf.gender = encrypGender.strip()
    conf.health = encrypHealth.strip()
    conf.maxHealth = encrypMaxHealth.strip()
    conf.armour = encrypArmour.strip()
    conf.maxArmour = encrypArmour.strip()
    conf.healthPotions = encrypHealthPotions.strip()
    conf.exp = encrypExp.strip()
    conf.maxExp = encrypMaxExp.strip()
    conf.level = encrypLevel.strip()
    conf.gold = encrypGold.strip()
    conf.maxGold = encrypMaxGold.strip()
    conf.powerLevel = encrypPowerLevel.strip()
    conf.maxPowerExp = encrypMaxPowerExp.strip()
    conf.powerExp = encrypPowerExp.strip()
    conf.stage = encrypStage.strip()
    return conf

and agMain.py

import agRead
while True:
    conf = agRead.read()
    if conf.stage == 1:

Upvotes: 0

melpomene
melpomene

Reputation: 85767

https://docs.python.org/3/tutorial/controlflow.html#defining-functions:

More precisely, all variable assignments in a function store the value in the local symbol table; whereas variable references first look in the local symbol table, then in the local symbol tables of enclosing functions, then in the global symbol table, and finally in the table of built-in names. Thus, global variables cannot be directly assigned a value within a function (unless named in a global statement), although they may be referenced.

Assigning to a variable in a function implicitly creates a local variable in that function, unless you've declared it as global.

Upvotes: 1

Related Questions