简体   繁体   中英

Best way to use variables across modules? (Python3)

I'm trying to separate various functions in my program to keep things neat. And I'm getting stuck trying to use variables created in one module in another module. I tried using global list_of_names but it wasn't working, and I've read that it's recommended not to do so anyway.

Below is a sample of my code. In my opinion, it doesn't make sense to pass list_of_names as a function argument because there are multiple other variables that I need to do this with, aside from the actual arguments that do get passed.

Unfortunately, even if I were to move read_json into engine.py, I'd still have the same problem in main.py as I need to reference list_of_names there as well.

# main.py:
import json
from engine import create_person
def read_json():
    with open('names.json', 'r') as file
        data = json.load(file)
    return data
list_of_names = read_json()
person1 = create_person()

# engine.py:
from random import choice
def create_person():
    name = choice(list_of_names)
    new_person = {
        'name': name,
        # other keys/values created in similar fashion
    }
    return new_person

EDIT1: Here's my new code. To me, this doesn't seem efficient to have to build the parameter list and then deconstruct it inside the function. (I know I'm reusing variable names for this example) Then I have to pass some of those parameters to other functions.

# main.py:
import json
from engine import create_person
def read_json():
    with open('names.json', 'r') as file
        data = json.load(file)
    return data

player_id_index = 0
list_of_names = read_json()
person_parameters = [
    list_of_names,
    dict_of_locations,
    player_id_index,
    dict_of_occupations,
    .
    .
    .
]

person1, player_id_index = create_person()

# engine.py:
from random import choice
def create_person(person_params):
    list_of_names = person_params[0]
    dict_of_locations = person_params[1]
    player_id_index = person_params[2]
    dict_of_occupations = person_params[3]
    .
    .
    .
    attr = person_params[n]

    name = choice(list_of_names)
    location = get_location(dict_of_locations) # a function elsewhere in engine.py
    p_id = player_id_index
    occupation = get_occupation(dict_of_occupations) # a function elsewhere in engine.py

    new_person = {
        'name': name,
        'hometown': location,
        'player id': p_id,
        'occupation': occupation,
        .
        .
        .
    }

    player_id_index += 1
    return new_person, player_id_index

In general you should not be relying on shared global state. If you need to share state encapsulate the state in objects or pass as function arguments.

Regarding your specific problem it looks like you want to assemble random dictionaries from a set of options. It could be coded like this:

from random import choice

person_options = {
   'name': ['fred', 'mary', 'john', 'sarah', 'abigail', 'steve'],
   'health': [6, 8, 12, 15],
   'weapon': ['sword', 'bow'],
   'armor': ['naked', 'leather', 'iron']
}

def create_person(person_options):
    return {k:choice(opts) for k, opts in person_options.items()}

for _ in range(4):
    print create_person(person_options)

In action:

>>> for _ in range(4):
...     print(create_person(person_options))
...
{'armor': 'naked', 'weapon': 'bow', 'health': 15, 'name': 'steve'}
{'armor': 'iron', 'weapon': 'sword', 'health': 8, 'name': 'fred'}
{'armor': 'iron', 'weapon': 'sword', 'health': 6, 'name': 'john'}
{'armor': 'iron', 'weapon': 'sword', 'health': 12, 'name': 'john'}

Note that a dictionary like {'armor': 'naked', 'weapon': 'bow', 'health': 15, 'name': 'steve'} looks like it might want to be an object. A dictionary is a glob of state without any defined behavior. If you make a class to house this state the class can grow methods that act on that state. Of course, explaining all this could make this answer really really long. For now, just realize that you should move away from having shared state that any old bit of code can mess with. A little bit of discipline on this will make your code much easier to refactor later on.


This addresses your edited question:

from random import choice
from itertools import count
from functools import partial

person_options = {
   'name': partial(
         choice, ['fred', 'mary', 'john', 'sarah', 'abigail', 'steve']),
   'location': partial(
         get_location, {'heaven':1, 'hell':2, 'earth':3}),
   'player id': count(1).next
}

def create_person(person_options):
    return {k:func() for k, func in person_options.items()}

However, we are now way beyond the scope of your original question and getting into specifics that won't be helpful to anyone other than you. Such questions are better asked on Code Review Stack Exchange

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM