Design advice (python question)

Have just completed a code cleanup/restructure on my project. Had about 1600 lines in 1 file and lots of global functions. (wow that prototype grew quickly!)

It is now spread across 3 files, 4 classes and very few (3, i think global functions). I have done OOP coding before, but not in Python, so my main issue was learning the syntax, etc. Once I figured that out, it was actually pretty straightforward to convert the structured code I had been using to OOP. And it all works smoothly and is easier to follow, IMO. (there’s more OOP opportunities to come, I’m sure)

My question is a Python one. I had used “global” variables in my original file to store some info like filepaths, game options, etc. that I calculate at the start of my program. I would like to have them all in 1 place for easy config, etc. , but they are required sometimes by classes now in different files.

How should I organize this?
Is there a way that I can make the variables accessible to all modules easily? (put them in their own module?), etc? what’s a good approach?

My favorite is:

class Globals:
   x, y, z

It can be passed to other modules:

othermod.func( Globals )

The drawback is, you can’t call functions from within the namespace that assign to it; you have to wait until its definition is completed.

class Globals:
   @staticmethod
   def funcA( ):
      stuff( )           # ok
      Globals.x = None   # ok, but
   funcA( )    ## NOT OK

You might be able to pull it off with a metaclass or class wrapper.

The traditional approach is to just make it a module, or make a global instance of some class that’s just slightly more work to define.

I"m doing the exact same thing with some of my custom classes. Here’s an example, my assetLoader:

import sys,os
from pandac.PandaModules import Filename
from direct.showbase.Loader import Loader
from direct.actor.Actor import Actor
from pandac.PandaModules import EggData
import re
from direct.stdpy.file import *

class AssetLoader:
	def __init__(self):
		self.loadPath = os.path.abspath(sys.path[0])
		self.loadPath = Filename.fromOsSpecific(self.loadPath).getFullpath()
		self.loadPath = self.loadPath + "/Assets/"
		self.loadPath = re.sub("Code/", "", self.loadPath)
		return
	
	def loadModel(self, modelName):
	
		return(loader.loadModel(self.loadPath + "Models/" + modelName))

	def loadActor(self, actorName):
		tempNode = Actor(self.loadPath + "Models/" + actorName)
		return tempNode

	def loadTexture(self, t1Name, t2Name = None):
		if(t2Name == None):	return(loader.loadTexture(self.loadPath + "Images/" + t1Name))
		else: return(loader.loadTexture(self.loadPath + "Images/" + t1Name, self.loadPath + "Images/" + t2Name))

		
	def loadEgg(self, eggName):
	
		tempNode = EggData()
		tempPath = Filename(self.loadPath + "Models/" + eggName)		
		tempNode.read(tempPath)
		return(tempNode)


	def loadFile(self, file, mode):
		file = open(self.loadPath + "Data/" + file, mode)
		return(file)

I create an instance of this class when the game is created, and I pass it to other classes that need to load assets. If they load assets at some point other than in their init function, they keep a reference to it. Otherwise, they just use it and then discard their temporary references.

This is much the same as the Globals class Castironpi uses, except instead of having global variables I give classes access to one another. For example, vehicles in my game need access to the track markers on the tracks they race on, both for AI piloting and also to record laps, etc. They also need access to the track’s gravity variable when they go over a jump. Instead of putting those things in global variables, I give the cycles a reference to the track and they can pull what they need from it.

I have no idea if this applies to your situation, but you made me think of a “decaying cache”, that stores the last ten entries in a dict (and a deque for tracking sequential order).

With well thought out modularity you don’t need any globals (or very few).

If you’re sure you need a globally available config, why don’t you simply create a ‘config’ module that is imported here and there? I imagine a class with a generate() classmethod that is called upon start or a wrapper for saving options back to files if changed ingame.