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?CommentedNov 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
      CommentedDec 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
      CommentedDec 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.

      Start asking to get answers

      Find the answer to your question by asking.

      Ask question

      Explore related questions

      See similar questions with these tags.