10

I received a project from developer who left our company. Not too complex, but it doesn't look very nice. So here is the question: Application has some modules and one is "settings" which stores some app. options (not all possible options, lets say just two: foo and bar). When application is started it reads options from command line (using argparse):

parser.add_argument('--foo', action='store_true')
parser.add_argument('--bar', action='store_true')
parser.add_argument('--baz', action='store_true')

And then it performs this nasty thing:

for name, val in parser.parse_args(sys.argv[1:])._get_kwargs():
    setattr(sys.modules['settings'], name, val)

First: I think this is dirty, non-pythonic hack. And second, it is simply inconvenient to use such code, because when I need to use settings.baz, IDE complaints that it doesn't exist. The intention of this hack is to make options parsed from command line available in all modules that are used in application further.

I'm thinking about something like singleton pattern, but I only used it once in PHP, and don't know if this correct solution in python. And even if it is, can someone show example?

I'm noob in python and on SO, please be kind to me :) Thanks.

p.s. I'm sorry for possible mistakes in my English

martineau
  • 119,623
  • 25
  • 170
  • 301
user2410235
  • 103
  • 1
  • 1
  • 4

2 Answers2

10

Modules in Python are singleton objects, and using one to store the settings used by the other modules would be a very Pythonic

The second line of the "nasty thing" is just setting the attributes of a module named settings and so isn't that bad. What's worse is the _get_kwargs() part of the first line which is accessing a private attribute of the argparse.Namespace object returned by parser.parse_args() to get the names and values of the settings parsed from the command-line. A slightly better way to do it might be something like this:

import settings  # possibly empty .py file

for name, val in vars(parser.parse_args(sys.argv[1:])).iteritems():
    setattr(settings, name, val)

However this won't fix your IDE problems because the IDE doesn't know the name of settings added dynamically. A simple way to fix that would be to define all the possible attributes with some kind of default values in a settings.py module instead of having an empty one.

The first time a module is imported an entry for it is added to the sys.modules dictionary with its name as the key and an instance of types.ModuleType as a value. Subsequent imports will first check to see if an entry for it already exists and will skip reloading the file if it does -- which is why I claim they're basically singleton objects. Modifications made to its attributes will immediately be visible to other modules that have imported it or do so afterwards, so it's generally a good data sharing mechanism within an application.

martineau
  • 119,623
  • 25
  • 170
  • 301
  • 1
    This is what I was looking for. Additionally I found this [link](http://docs.python.org/2/faq/programming.html#how-do-i-share-global-variables-across-modules), which just confirms your answer. Regarding the "nasty thing" - you are right, the most confusing thing was usage of private method. Thanks for the hint with `vars`. And of course thank you for detailed explanation of how all these works. – user2410235 May 22 '13 at 19:16
  • It's good to see they've explicitly documented this usage of modules in the FAQ. Although `sys.modules` purpose is to provide a module caching mechanism, the implementation makes them particularly well suited for exchanging data among modules within the application. – martineau May 22 '13 at 21:20
  • 2
    FWIW There's also a section titled [How do I share global variables across modules?](https://docs.python.org/3/faq/programming.html#how-do-i-share-global-variables-across-modules) in the current Python 3 documentation that has the same advice (call it the "canonical" way to do this sort of thing). – martineau Jan 13 '18 at 21:13
0

Look this Config (A hierarchical, easy-to-use, powerful configuration module for Python )

Detailed doc & examples

Roman Podlinov
  • 23,806
  • 7
  • 41
  • 60
  • 1
    Yeah, I saw this module, but it's rather about cool config format than what I need. I fact, the question is how to share config across all modules in application. No matter if these options from config file or command line. Probably I don't see eviden things and this module has what I need, but please note, I'm noob in python (and don't have too much experience in programming at all). So it would be nice if you can point me how to use it in my case. – user2410235 May 22 '13 at 16:19