1

I have found myself in the habit of using code like this.

class glb:
    "just for holding globals"
    args = None  # from argparse
    conf = None  # from configparser

def main():
    ...
    glb.args = parser.parse_args()
    glb.conf = loadconf(fn)

Assuming there is a case for using globals, I feel that this is a nice and clean way of doing it. It's a kind of a singleton pattern.

It’s simpler to spot thee glb. prefix than standard globals. However, I don't write that much object-oriented Python or larger projects, so I'm uncertain if there could be side effects or other gotchas that I'm not aware of.

So in short: Are there any downsides to doing it like this? Does it smell? Is there a better more pythonic way?

2 Answers 2

3

Using a class merely as a namespace rather than as a construct for objects strikes me as a bit unpythonic. Yes, it works just fine. But that's not how classes are normally used, and therefore potentially confusing.

Other than grouping the application state, there seems to be no advantage over just using ordinary globals:

ARGS = None
CONF = None

def main():
  ARGS = parser.parse_args()
  CONFG = loadconf(fn)

If you want an object that represents the application state, consider creating such an object as usual. For example:

@dataclass
class AppState:
  args: Args
  conf: Config

APP: Optional[AppState] = None

def main():
  APP = AppState(
    args=parser.parse_args(),
    config=loadconf(fn),
  )
3
  • Tanks! Pylint will complain 'redefined-outer-name' for the first version and complain about the 'global' statement if I use that, but the initial idea was just to prefix all my globals for readability and then a "real prefix" seemed better than just a convention. The dataclass example is something I will have to look into more closely. Especially if you tell me this is a common pattern. But why use an instance when the class will suffice? Commented Nov 29, 2022 at 15:51
  • The first example should include global ARGS, CONF as the first line of main. Currently, ARGS and CONFG (sic) are local variables inside main, independent of the globals of the same and similar name. In other functions, ARGS and CONF would still be None.
    – Jasmijn
    Commented Dec 1, 2022 at 15:14
  • The object-based approach is definitely the way to go. The AppState class makes it really clear what the result of parsing arguments should be, and what's necessary for loading the app's configuration
    – Alexander
    Commented Dec 22, 2022 at 22:30
1

Zen of python says "Namespaces are one honking great idea -- let's do more of those!".

Implies the following is pythonic.

do_thing(vars.important_value)

When we include the import of vars as a module in our example; is this still pythonic?

import vars
do_thing(vars.important_value)

How about if we change how it's imported; is it still pythonic?

from some_module import vars
do_thing(vars.important_value)

How about when we use an instance of a class?

class Vars:
    def __init__(iv):
        self.important_value = iv
vars = Vars(1234)

do_thing(vars.important_value)

That last bit is what got me. If instantiating a class is the key to creating a namespace outside of a module in order be pythonic, that would seem to contradict "simple is better"

It's for this reason I say using an uninstantiated class as a namespace is indeed pythonic, even if not often used.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.